# Tilopay Portal para Desarrolladores y Agentes AI — texto completo > Documentación técnica de Tilopay (SDK, API, webhooks, pruebas) en Markdown, sin nada normativo dentro de imágenes. Idioma: español. Índice: https://tilopay.com/llms.txt ## Artefactos legibles por máquina - [openapi.json](https://tilopay.com/developers/openapi.json): Spec OpenAPI 3.1 del API de Tilopay, fuente de verdad de endpoints, parámetros y respuestas. - [openapi.yaml](https://tilopay.com/developers/openapi.yaml): El mismo spec, en YAML. - [mcp.json](https://tilopay.com/developers/mcp.json): Catálogo de las herramientas del servidor MCP de Tilopay, con parámetros, salidas y nivel de acceso. - [api-bancario/openapi.json](https://tilopay.com/developers/api-bancario/openapi.json): Spec OpenAPI 3.0.3 del API Bancario (BaaS) de Tilopay, versión 1.0.0, artefacto separado del API de adquirencia. - [api-bancario/openapi.yaml](https://tilopay.com/developers/api-bancario/openapi.yaml): El mismo spec, en YAML. - [skills/index.md](https://tilopay.com/developers/skills/index.md) - [cierre-de-caja/SKILL.md](https://tilopay.com/developers/skills/cierre-de-caja/SKILL.md) - [cobrar-por-whatsapp/SKILL.md](https://tilopay.com/developers/skills/cobrar-por-whatsapp/SKILL.md) - [rechazos-y-recuperacion/SKILL.md](https://tilopay.com/developers/skills/rechazos-y-recuperacion/SKILL.md) - [conciliacion-mensual/SKILL.md](https://tilopay.com/developers/skills/conciliacion-mensual/SKILL.md) - [cfo-de-bolsillo/SKILL.md](https://tilopay.com/developers/skills/cfo-de-bolsillo/SKILL.md) - [catalogo-y-cobros-fijos/SKILL.md](https://tilopay.com/developers/skills/catalogo-y-cobros-fijos/SKILL.md) --- # Tilopay para desarrolladores > Los cuatro caminos de integración, el contrato de campos, la referencia del SDK, el API y webhooks. - kind: guide - status: stable - last_verified: 2026-08-29 - url: https://tilopay.com/developers Paso 0: no hay credenciales de sandbox compartidas. Cada desarrollador se registra y recibe las suyas en https://tilopay.com/developers/registro ## Cuatro caminos de integración - **Sin código** — extensiones y plugins para plataformas existentes: /developers/sin-codigo - **Hosted payment page** — tu servidor pide una URL al API y redirige al cliente a una página de Tilopay: /developers/hosted-payment-page - **SDK JavaScript** — los campos de tarjeta viven en tu página y el SDK los manda directo a Tilopay; acepta tarjetas, SINPE Móvil y Apple Pay: /developers/sdk - **API servidor a servidor** — acceso restringido a comercios con certificación PCI; la URL se provisiona por comercio: /developers/server-to-server ## Referencia - Spec OpenAPI 3.1: /developers/openapi.json - API Adquirencia: /developers/api/autenticacion - Webhooks: /developers/api/webhooks - Campos del formulario: /developers/sdk/campos-del-formulario - Apple Pay con el SDK: /developers/sdk/apple-pay - API Bancario (acceso restringido): /developers/api-bancario - Spec OpenAPI 3.0.3 del API Bancario: /developers/api-bancario/openapi.json --- # Registro como desarrollador > Cómo obtener credenciales de sandbox para probar las integraciones de Tilopay. - kind: guide - status: stable - last_verified: 2026-08-29 - url: https://tilopay.com/developers/registro No existen credenciales de sandbox compartidas ni públicas: cada desarrollador se registra y recibe las suyas. Es el paso previo a cualquiera de los cuatro caminos de integración. ## Cómo obtenerlas 1. Completá el registro de desarrollador en https://tilopay.com/developers/registro 2. Tilopay habilita una cuenta de pruebas y entrega las credenciales de ese comercio. 3. Con esas credenciales se obtiene el token del API (/developers/api/autenticacion) o el token del SDK. ## Pruebas y producción No hay un host de sandbox separado: el modo de pruebas se activa desde la cuenta del comercio. Ver /developers/entornos --- # Integración sin código > Integración sin código: plugins y conectores para Shopify, WooCommerce, Wix, VTEX y PMS hoteleros. - kind: guide - status: stable - last_verified: 2026-08-29 - url: https://tilopay.com/developers/sin-codigo Es el camino de menor fricción: el comercio instala el plugin o el conector de su plataforma y configura Tilopay como método de pago desde el panel de esa plataforma. No se escribe código y los datos de tarjeta no pasan por el comercio. ## Plataformas con plugin o conector El directorio lista 83 plataformas, cada una con su guía de instalación cuando existe. ### E-commerce - **Shopify** — La única integración nativa en Centroamérica certificada por Shopify desde 2022. Activa Tilopay en tu tienda, recibe tarjetas de cualquier banco y expande tus ventas por la región sin límites. (https://tilopay.com/plataformas/shopify) - **Wix** — Integra el plug-in nativo más confiable de Centroamérica y el Caribe a tu página en Wix. Acepta tarjetas Mastercard, Visa y American Express sin complicaciones. (https://tilopay.com/plataformas/wix) - **WooCommerce** — Integra el plug-in certificado de Tilopay por WooCommerce en tu página web. Acepta tarjetas Mastercard, Visa y American Express sin complicaciones. (https://tilopay.com/plataformas/woocommerce) - **VTEX** — Acepta tarjetas Mastercard, Visa y American Express sin complicaciones en tu tienda online VTEX de Centroamérica y el Caribe. (https://tilopay.com/plataformas/vtex) - **Avify** — La integración de Tilopay a Avify para cobrar con tarjeta por WhatsApp para Centroamérica y el Caribe. (https://tilopay.com/plataformas/avify) - **Take.App** — Vende por WhatsApp con tu catálogo en línea de Take.App y cobra con tarjetas Mastercard, Visa y American Express mediante Tilopay. - **Blume** — Acepta tarjetas Mastercard, Visa y American Express sin complicaciones en tu tienda online Blume de Centroamérica y el Caribe. - **BigCommerce** — Acepta tarjetas Mastercard, Visa y American Express sin complicaciones en tu tienda online en BigCommerce de Centroamérica y el Caribe. - **Adobe Commerce / Magento** — Extensión oficial de Tilopay para Adobe Commerce y Magento Open Source 2.4. Cobra con tarjeta dentro de tu propio checkout, con 3DS, cuotas Tasa 0, SINPE Móvil, Yappy y Apple Pay. (https://tilopay.com/plataformas/adobe-commerce-cloud) - **Ecwid** — Acepta tarjetas Mastercard, Visa y American Express sin complicaciones en tu tienda online Ecwid de Centroamérica y el Caribe. ### Hospedaje y PMS - **Cloudbeds** — Centraliza la gestión de tu hotel y acepta pagos de todo el mundo con tarjetas Mastercard, Visa y American Express de forma fluida a través de Cloudbeds. (https://tilopay.com/plataformas/cloudbeds) - **Bookinglayer** — Acepta tarjetas Mastercard, Visa y American Express de todo el mundo, sin complicaciones a través de Bookinglayer. (https://tilopay.com/plataformas/bookinglayer) - **Orbe Booking** — Acepta tarjetas Mastercard, Visa y American Express de todo el mundo en tus reservas, sin complicaciones utilizando el motor de reservas en línea Orbe. (https://tilopay.com/plataformas/orbe-booking) - **Mangobeds** — Impulsa las reservas directas de tu alojamiento y acepta las principales tarjetas del mundo sin complicaciones utilizando el motor de Mangobeds. - **ChargeAutomation** — Acepta tarjetas Mastercard, Visa y American Express de todo el mundo, sin complicaciones a través de ChargeAutomation. (https://tilopay.com/plataformas/chargeautomation) - **ThinkReservations** — Aumenta tus reservas, simplifica operaciones y construye un negocio más rentable con nuestra integración en ThinkReservations. - **SimpleBooking** — Acepta tarjetas Mastercard, Visa y American Express de todo el mundo en tus reservas, sin complicaciones utilizando el motor de reservas en línea SimpleBooking. - **Avantio** — Acepta tarjetas Mastercard, Visa y American Express sin complicaciones en tu negocio en Avantio de Centroamérica y el Caribe. - **Opera** — Optimiza la operación de tu hotel y procesa los pagos de tus huéspedes con tarjetas Mastercard, Visa y American Express de forma segura a través de Opera. - **Booking Automation** — Integración disponible a través de ChargeAutomation. - **Smoobu** — Integración disponible a través de ChargeAutomation. - **Clock** — Integración disponible a través de ChargeAutomation. - **Beds24** — Integración disponible a través de ChargeAutomation. - **Guesty** — Integración disponible a través de ChargeAutomation. - **Tokeet** — Integración disponible a través de ChargeAutomation. - **Hostaway** — Integración disponible a través de ChargeAutomation. - **Hostfully** — Integración disponible a través de ChargeAutomation. - **OwnerRez** — Integración disponible a través de ChargeAutomation. - **Hospitable** — Integración disponible a través de ChargeAutomation. - **Godo** — Integración disponible a través de ChargeAutomation. - **Hosthub (Syncbnb)** — Integración disponible a través de ChargeAutomation. - **Hostify** — Integración disponible a través de ChargeAutomation. - **Uplisting** — Integración disponible a través de ChargeAutomation. - **Lodgify** — Integración disponible a través de ChargeAutomation. - **BookingSync** — Integración disponible a través de ChargeAutomation. - **myVR** — Integración disponible a través de ChargeAutomation. - **Protel** — Integración disponible a través de ChargeAutomation. - **AbodeBooking** — Integración disponible a través de ChargeAutomation. - **Brillantez Solutions** — Integración disponible a través de ChargeAutomation. - **GuestCentrix** — Integración disponible a través de ChargeAutomation. - **Easyrez** — Integración disponible a través de ChargeAutomation. - **eZee Absolute** — Integración disponible a través de ChargeAutomation. - **eZee FrontDesk** — Integración disponible a través de ChargeAutomation. - **FNSROOMS** — Integración disponible a través de ChargeAutomation. - **Front2Go** — Integración disponible a través de ChargeAutomation. - **Hotellinking** — Integración disponible a través de ChargeAutomation. - **Hoteliga** — Integración disponible a través de ChargeAutomation. - **Hoteltime Solutions** — Integración disponible a través de ChargeAutomation. - **InnKey** — Integración disponible a través de ChargeAutomation. - **Little Hotelier** — Integración disponible a través de ChargeAutomation. - **Mews** — Integración disponible a través de ChargeAutomation. - **MisterBooking** — Integración disponible a través de ChargeAutomation. - **NewBook** — Integración disponible a través de ChargeAutomation. - **Occupancy Plus** — Integración disponible a través de ChargeAutomation. - **Preno** — Integración disponible a través de ChargeAutomation. - **Resort Data Processing** — Integración disponible a través de ChargeAutomation. - **Roomraccoon** — Integración disponible a través de ChargeAutomation. - **Room Ranger** — Integración disponible a través de ChargeAutomation. - **Shalom** — Integración disponible a través de ChargeAutomation. - **Sirvoy** — Integración disponible a través de ChargeAutomation. - **Ulyses Cloud** — Integración disponible a través de ChargeAutomation. - **VHP** — Integración disponible a través de ChargeAutomation. - **Winhms** — Integración disponible a través de ChargeAutomation. - **W2** — Integración disponible a través de ChargeAutomation. - **Zavia ERP** — Integración disponible a través de ChargeAutomation. - **3RPMSa** — Integración disponible a través de ChargeAutomation. - **Autoclerk** — Integración disponible a través de ChargeAutomation. - **Hansaworld** — Integración disponible a través de ChargeAutomation. - **Hotel Link Solutions** — Integración disponible a través de ChargeAutomation. - **Ibelsa** — Integración disponible a través de ChargeAutomation. - **Revenue Control Data** — Integración disponible a través de ChargeAutomation. - **Roomer** — Integración disponible a través de ChargeAutomation. - **Servo IT Solutions** — Integración disponible a través de ChargeAutomation. - **Softmogul** — Integración disponible a través de ChargeAutomation. - **Suitech** — Integración disponible a través de ChargeAutomation. - **Thais Soft** — Integración disponible a través de ChargeAutomation. - **TK Technology** — Integración disponible a través de ChargeAutomation. - **Sympl** — Integración disponible a través de ChargeAutomation. - **5Stelle** — Integración disponible a través de ChargeAutomation. - **Planyo** — Integración disponible a través de ChargeAutomation. ### Servicios y reservas - **Wstudio.app** — Acepta tarjetas Mastercard, Visa y American Express de todo el mundo, sin complicaciones a través de Wstudio.app. (https://tilopay.com/plataformas/wstudio-app) - **SimplyBook** — Facilita la agenda de tus clientes y automatiza el cobro de tus citas con tarjetas Mastercard, Visa y American Express mediante SimplyBook. ### ERP y CRM - **Odoo ERP & CRM** — Integra el software empresarial Odoo con Tilopay para aceptar pagos en diversos métodos. --- # Autenticación > Cómo obtener el token del API y el token del SDK, cuánto duran y cómo se envían en cada llamada. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/autenticacion Todo el API y el SDK viven en un único host: `https://app.tilopay.com`. No hay un host distinto para pruebas — ver [entornos](/developers/entornos). ## Las dos operaciones [#operaciones] | Operación | Ruta | Para qué | |---|---|---| | Token del API | `POST /api/v1/login` | Llamadas servidor a servidor al API | | Token del SDK | `POST /api/v1/loginSdk` | El token que se le pasa a `Tilopay.Init()` | ## Obtener el token del API [#token-api] ```bash curl -X POST https://app.tilopay.com/api/v1/login \ -H "Content-Type: application/json" \ -d '{ "apiuser": "TU_APIUSER", "password": "TU_PASSWORD" }' ``` ### Cuerpo [#cuerpo] Usuario de API del comercio. Contraseña de API del comercio. ### Respuesta [#respuesta] El token que se envía en las llamadas siguientes. Siempre `bearer`. Vigencia del token como **entero en segundos** (por ejemplo `86400`). El tiempo exacto viene en esta respuesta: no lo asumás desde el cliente. ## Obtener el token del SDK [#token-sdk] ```bash curl -X POST https://app.tilopay.com/api/v1/loginSdk \ -H "Content-Type: application/json" \ -d '{ "apiuser": "TU_APIUSER", "password": "TU_PASSWORD", "key": "TU_API_KEY" }' ``` El token resultante es el que se pasa al parámetro `token` de [`Tilopay.Init()`](/developers/sdk/reference/init). ## Vigencia [#vigencia] - **Token del API: 24 horas.** `expires_in` llega como **entero en segundos** (por ejemplo `86400`). - **Token del SDK: 1 hora.** `expires_in` llega como **fecha-hora en texto** (por ejemplo `"2023-06-05 13:32:06"`). El valor exacto siempre llega en `expires_in`, en el formato de cada operación. Cachealo del lado servidor y renovalo cuando expire. ## Cómo se envía [#envio] ```http Authorization: bearer ``` ## Revocación y límites [#revocacion] - **Los tokens no se pueden revocar.** Si un token se filtra, no hay una operación para invalidarlo: hay que tratar la fuga como un incidente y rotar credenciales con Tilopay. - **No hay límite** de tokens simultáneos por comercio. Podés pedir uno por proceso sin invalidar los anteriores. ## Dónde se obtienen las credenciales [#credenciales] `apiuser`, `password` y `key` se obtienen en el panel del comercio, en [Panel administrativo · Integración con plataformas](https://admin.tilopay.com/platform-integrations). Si no tenés acceso todavía, empezá por [el registro de developer](/developers/registro). > **Advertencia:** Nunca pongas `apiuser` ni `password` en el navegador. El login corre en tu servidor; al > navegador solo baja el token del SDK. --- # Hosted payment page > Camino de integración en el que el cliente paga en una página alojada por Tilopay y tu servidor recibe el resultado. - kind: guide - status: stable - api_version: v1 - last_verified: 2026-08-28 - url: https://tilopay.com/developers/hosted-payment-page ## Qué es [#que-es] Tu servidor le pide una URL de pago al API, redirige al cliente a esa página de Tilopay y recibe el resultado en tu callback URL. Los datos de tarjeta se digitan en una página de Tilopay: **vos nunca ves un número de tarjeta** y tu servidor queda fuera de ese flujo, lo que reduce al mínimo tu alcance PCI. La operación de este camino está en [API · processPayment](/developers/api/hosted-payment-page/process-payment). ## Diferencia con un link de pago [#diferencia-link] - **Hosted payment page**: tu servidor pide una URL de pago por API y redirige al cliente a ella. Es ideal para flujos de checkout integrados en tu sitio o app. - **Link de pago**: es una URL reusable que creás por API o desde el panel y compartís por mensaje, correo, redes o QR. El cliente paga cuando quiera; no necesitás redirigirlo desde tu flujo. - En resumen: HPP para checkout integrado y transacciones puntuales; link de pago para cobros compartidos y sin desarrollo de front. ## Para quién es [#para-quien] Para equipos que cobran con código propio pero prefieren no construir ni mantener el formulario de tarjeta. Lo que necesitás es backend: pedir la URL y atender el callback. ## Requisitos antes de empezar [#requisitos] 1. **Credenciales propias.** No hay credenciales de sandbox compartidas: cada desarrollador obtiene las suyas en [registro de developer](/developers/registro). 2. **Autenticación del API.** Ver [autenticación](/developers/api/autenticacion). 3. **Una URL de callback tuya** que pueda recibir el resultado de la transacción. ## Cómo confirmar el estado de un cobro [#confirmacion] El resultado que llega a tu callback no es la única señal disponible, y no todas las respuestas de error viajan con un HTTP 4xx: - Leé [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors) antes de decidir un éxito. - Configurá [webhooks](/developers/api/webhooks) para los eventos que te interesen. - Si una llamada falla sin respuesta clara, resolvé el estado con [reintentos seguros](/developers/reintentos-seguros). ## Entornos [#entornos] Pruebas y producción comparten el mismo host. Ver [entornos](/developers/entornos) antes de cobrar de verdad. ## Cumplimiento [#cumplimiento] Es el camino que menos expone a tu infraestructura junto con el de sin código. Confirmá con tu equipo de cumplimiento el alcance que aplica a tu comercio. ## Si preferís el formulario en tu sitio [#alternativa] Usá el [SDK JavaScript](/developers/sdk): el diseño es tuyo y los datos siguen sin pasar por tu servidor. --- # Entornos: pruebas y producción > Pruebas y producción comparten host. El modo se cambia desde la cuenta y se verifica con el campo environment de Init(). - kind: concept - status: stable - api_version: v1 - last_verified: 2026-10-21 - url: https://tilopay.com/developers/entornos > **Advertencia:** No existe un host de sandbox. Pruebas y producción usan el mismo host: > `app.tilopay.com`. La URL no te dice en qué modo estás. ## Cómo se cambia de modo [#como-se-cambia] El modo se alterna **desde la cuenta en el portal de Tilopay**, no desde la integración. No hay un parámetro, un encabezado ni una URL alterna que lo cambie desde el código. ## Cómo se verifica [#como-se-verifica] `Tilopay.Init()` devuelve un campo **`environment`**: | Valor | Significado | |---|---| | `"PROD"` | Producción | | `"TEST"` | Pruebas | Esa es la única señal disponible en tiempo de ejecución. Leela y mostrala en tu propio checkout mientras desarrollás. ## El riesgo real [#riesgo] > **Advertencia:** Como el host es el mismo, un integrador puede creer que está probando y estar en > producción, cobrando de verdad. Verificá que `environment` sea `"TEST"` antes de asumir > que estás en pruebas; hacé que un `"PROD"` inesperado falle ruidosamente en desarrollo. ## Tarjetas de prueba [#tarjetas] En modo de pruebas se cobra con las [tarjetas de prueba](/developers/tarjetas-de-prueba): ahí está el número, la marca, el resultado esperado y si abre la pantalla de challenge 3DS. --- # Tarjetas de prueba > Las 27 tarjetas del ambiente de pruebas de Tilopay, con el resultado esperado y la fricción 3DS de cada una. - kind: guide - status: stable - api_version: v1 - last_verified: 2026-10-21 - url: https://tilopay.com/developers/tarjetas-de-prueba Estas tarjetas sólo funcionan cuando la cuenta está en **modo de pruebas**. El modo se cambia desde la cuenta y se verifica con el campo `environment` que devuelve `Init()` (`"TEST"` en pruebas): ver [entornos y pruebas](/developers/entornos). ## Cómo se usan [#uso] | Dato | Qué se ingresa | | --- | --- | | Fecha de vencimiento | Cualquiera en el futuro | | CVV | Cualquiera | | Código de la pantalla de challenge 3DS | `3ds2` | > **Advertencia:** En la pantalla de challenge 3DS el código a ingresar es `3ds2`. No hay otro código ni se envía > por SMS en pruebas. ## Tarjetas [#tarjetas] La marca se deriva del prefijo: `4` Visa, `51`–`55` Mastercard, `34` American Express. | Número | Marca | Resultado esperado | Fricción | | --- | --- | --- | --- | | `4111111111111111` | Visa | Aprobada | Sin fricción | | `4012000000020089` | Visa | Aprobada | Sin fricción | | `4012000000020006` | Visa | Aprobada | Sin fricción | | `4012010000020088` | Visa | Aprobada | Sin fricción | | `5100270000000072` | Mastercard | Aprobada | Sin fricción | | `5100270000000031` | Mastercard | Aprobada | Sin fricción | | `341111000000009` | American Express | Aprobada | Sin fricción | | `341111000000011` | American Express | Aprobada | Sin fricción | | `341112000000001` | American Express | Aprobada | Sin fricción | | `341111000000037` | American Express | Aprobada | Sin fricción | | `341112000008012` | American Express | Aprobada | Sin fricción | | `4012000000020071` | Visa | Aprobada | Challenge 3DS | | `4012010000020070` | Visa | Aprobada | Challenge 3DS | | `4012010000020005` | Visa | Aprobada | Challenge 3DS | | `5100270000000023` | Mastercard | Aprobada | Challenge 3DS | | `5100271000000120` | Mastercard | Aprobada | Challenge 3DS | | `4112613451591116` | Visa | Fondos insuficientes | Challenge 3DS | | `4523080346468525` | Visa | CVV incorrecto | Sin fricción | | `4549179990476733` | Visa | Tarjeta restringida | Sin fricción | | `4012000000020121` | Visa | Rechazada | Sin fricción | | `4111111111119999` | Visa | Rechazada | Sin fricción | | `4111111111110000` | Visa | Rechazada | Sin fricción | | `5100270000000056` | Mastercard | Rechazada | Sin fricción | | `5111111111113333` | Mastercard | Rechazada | Sin fricción | | `4666666666662222` | Visa | Rechazada | Sin fricción | | `5555666666662222` | Mastercard | Rechazada | Sin fricción | | `5100270000000098` | Mastercard | Rechazada | Challenge 3DS | Las tarjetas con fricción **Challenge 3DS** abren la pantalla de autenticación; las de **Sin fricción** resuelven sin pasar por ella. El resultado esperado es el mismo cada vez: la tarjeta determina la respuesta, no el monto. --- # Reintentos seguros y orderNumber > El API de adquirencia no es idempotente. Qué hacer exactamente cuando una llamada de pago se cae por timeout. - kind: concept - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/reintentos-seguros > **Advertencia:** El API de adquirencia de Tilopay no es idempotente. No existe una llave de idempotencia ni un reintento > que devuelva la transacción original. Si venís de otros procesadores, este es el supuesto que > tenés que desarmar antes de escribir código. ## `orderNumber` es único para siempre [#ordernumber] `orderNumber` es único por comercio **a lo largo de toda su operación**, para siempre. No se reinicia por día, por mes ni por temporada. Si se repite, **la nueva transacción se rechaza** con la respuesta **"Transacción duplicada"**. No devuelve la transacción original: devuelve un rechazo. ## El problema del timeout [#timeout] Cuando una llamada de pago se cae por red o por timeout, no sabés si la transacción se creó o no. Y ninguna de las dos salidas intuitivas sirve: | Qué harías | Qué pasa | |---|---| | Reintentar con el mismo `orderNumber` | Rechazo por duplicado, incluso si la primera sí pasó | | Reintentar con un `orderNumber` nuevo | Riesgo de doble cobro | **Ante un timeout de red no hay reintento seguro.** ## Qué hacer entonces [#que-hacer] Consultá el estado antes de decidir: 1. Llamá a `POST /api/v1/consult` con el `orderNumber` original. 2. Si la transacción existe, usá su resultado. No reintentés. 3. Si no existe, ahí sí podés reintentar — y podés reusar el mismo `orderNumber`, porque no se consumió. ```text pago → timeout │ └─→ consult(orderNumber original) ├─ existe → usar ese resultado └─ no existe → reintentar ``` ## Consecuencias de diseño [#diseno] - Generá el `orderNumber` en tu sistema **antes** de llamar al pago y persistilo. Si lo generás al vuelo, después de un timeout no tenés con qué consultar. - Nunca derives el `orderNumber` de algo que se pueda repetir (número de carrito reciclado, timestamp truncado, contador reiniciable). - Un "Transacción duplicada" no significa que el cobro falló: significa que ese `orderNumber` ya se usó. Consultá antes de mostrarle un error al cliente. --- # Cómo leer una respuesta de error > Un HTTP 200 no significa éxito. Dónde viene el rechazo del emisor y cómo escribir el manejo de errores. - kind: concept - status: stable - api_version: v1 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/api/procesos-operativos/errors ## El rechazo del emisor [#rechazo] Cuando el emisor rechaza una transacción, la respuesta trae dos campos: El código de rechazo del emisor. El texto del rechazo. ## Un HTTP 200 no significa éxito [#estado-http] > **Advertencia:** No hay un estándar definido de cuándo el API responde HTTP 4xx y cuándo responde HTTP 200 con > el error en el cuerpo. Conviven las dos formas, y hay cinco envolturas distintas de error > según el endpoint. > > Consecuencia práctica: tu manejo de errores tiene que mirar el cuerpo siempre, no solo el > código de estado, y tolerar más de una forma de cuerpo. ## Formas del cuerpo de error [#formas-del-cuerpo] Error de `processModification` (`type` 300 o 400): ```json {"type":"400","message":"Order number: TYP974_172 does not exist"} ``` Cinco envolturas distintas, según el endpoint: | Envoltura | Endpoints | |---|---| | `{"error": "Unauthorized"}` | `login`, `loginSdk` | | `{"type", "message"}` | `processPayment`, `processModification` | | `{"type", "result"}` | `processRecurrentPayment`, `processTokenize` | | `{"code", "description", "error"}` | servidor a servidor | | `{"code", "description"}` | rechazo del emisor | ## Cómo escribir el manejo de errores [#como-manejar] - Tratá `code` y `description` como datos para registrar y mostrar, no como una enumeración sobre la que ramificar. - No hagas `if (status === 200) éxito`. Verificá el cuerpo. - Guardá la respuesta cruda de cada rechazo: es lo que te permite reconstruir el patrón de rechazos de tu comercio. - Para decidir el estado real de una transacción después de un fallo, usá [reintentos seguros](/developers/reintentos-seguros). --- # API · Cuatro caminos de integración > Los cuatro caminos para cobrar con Tilopay y la diferencia que decide cuál te conviene: por dónde viajan los datos de tarjeta. - kind: concept - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/caminos-de-integracion ## Cuatro caminos [#cuatro-caminos] Hay cuatro formas de cobrar con Tilopay. Cambian en dos cosas: cuánto construís vos y dónde aparecen los campos de tarjeta. Elegí una y seguí su guía; todas empiezan con tus credenciales de sandbox, que se piden en el [registro de developer](/developers/registro). ### 1 · Sin código [#sin-codigo] Extensiones y plugins para plataformas existentes. No escribís una línea de código. [Ver camino](/developers/sin-codigo) ### 2 · Hosted payment page [#hosted-payment-page] Tu servidor pide una URL al API, redirige al cliente a esa página de Tilopay y recibe el resultado en tu callback URL. [Ver camino](/developers/hosted-payment-page) ### 3 · SDK JavaScript [#sdk-javascript] Los campos de tarjeta viven en tu página; el SDK los captura y los manda directo a Tilopay. [Ver camino](/developers/sdk) ### 4 · API servidor a servidor [#servidor-a-servidor] Acceso restringido: servicio exclusivo para comercios con certificación PCI. La URL se provisiona por comercio, no es pública. [Requisitos y solicitud](/developers/server-to-server) ## Cómo elegir [#como-elegir] Elegir mal sale caro. La diferencia que más importa es por dónde viajan los datos de tarjeta. | Camino | Quién construye el formulario | Por dónde viajan los datos de tarjeta | Qué se necesita saber | Implicación de cumplimiento | | --- | --- | --- | --- | --- | | 1 · Sin código | La plataforma | Nunca pasan por tus sistemas | Configuración en el panel de la plataforma | Consultá con tu equipo de cumplimiento | | 2 · Hosted payment page | Tilopay | Tu cliente los digita en una página segura de Tilopay; vos nunca ves un número de tarjeta | Backend: pedir la URL y recibir el callback | Consultá con tu equipo de cumplimiento | | 3 · SDK JavaScript | Tu sitio | Se digitan en tu página pero viajan del navegador directo a Tilopay; no pasan por tu servidor | Frontend con JavaScript, más backend para credenciales | Consultá con tu equipo de cumplimiento | | 4 · Servidor a servidor (acceso restringido) | Tu sitio | Los datos de tarjeta pasan por tu servidor | Requiere tu certificación PCI y URL provisionada por Tilopay | Consultá con tu equipo de cumplimiento | > **Advertencia:** El camino 4 no es de autoservicio: es exclusivo para comercios con certificación PCI y la URL > se provisiona individualmente. Además es el único que mete a tu servidor dentro del alcance de > PCI DSS. Los caminos 2 y 3 evitan ese costo y podés empezarlos hoy. ## Después de elegir [#despues-de-elegir] Con el camino elegido, seguí con [convenciones de las respuestas](/developers/api/convenciones) para saber cómo vienen tipados los montos, y con [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors) antes de poner el código en producción. [Referencia de cobros con tarjetas guardadas](/developers/api/cobros-tarjetas-guardadas). --- # API · Convenciones de las respuestas > Cómo vienen tipados los montos, dónde hay JSON dentro de una cadena y por qué la misma entidad cambia de forma entre consultar uno y listar. - kind: concept - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/convenciones Las respuestas del API de adquirencia tienen varios detalles que no se deducen leyendo cada operación por separado y que rompen integraciones tipadas. Están acá porque aplican a varias operaciones a la vez. Para el manejo de errores, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). ## Los montos vienen como cadena, no como número [#montos-cadena] > **Advertencia:** Los montos, descuentos e importes se serializan como cadena: `"discount": "40.00"`, > `"amount": "0.00"`, `"first_amount": "0.00"`, `"amount_max_daily": "1000.00"`. Cualquier deserialización tipada que declare esos campos como número falla. Declaralos como cadena y convertilos vos, con el tipo decimal de tu lenguaje, no con punto flotante. Aparece, entre otras, en [obtener un cupón](/developers/api/recurrentes/cupones/get-coupon), [listar cupones](/developers/api/recurrentes/cupones/get-coupons), [listar planes](/developers/api/recurrentes/planes/get-plans) y [pagos de suscriptor](/developers/api/recurrentes/suscriptores/suscriptor-payments). ## Hay un JSON dentro de una cadena [#doble-encoding] En [pagos de suscriptor](/developers/api/recurrentes/suscriptores/suscriptor-payments), el campo `data` de cada pago **no es un objeto: es una cadena que contiene JSON**. ```json "data": "{\"first\":1,\"expire\":\"2024-12-28T19:05:29.572648Z\",\"amount\":0,\"activeAmount\":0,\"originalAmount\":0,\"key\":\"XXXX-XXXX-XXXX-XXXX-XXXX\"}" ``` Hay que deserializar dos veces: primero la respuesta, después el contenido de `data`. Tratá esa segunda deserialización como puede fallar cualquier entrada externa: envolvela y registrá la cadena cruda si no parsea. ## La misma entidad cambia de forma entre "obtener uno" y "listar" [#uno-vs-lista] No es un descuido de la documentación: las dos operaciones devuelven formas distintas del mismo cupón, y hay que mapearlas por separado. | | [`getCoupon`](/developers/api/recurrentes/cupones/get-coupon) (uno) | [`getRepeatCoupons`](/developers/api/recurrentes/cupones/get-coupons) (lista) | | --- | --- | --- | | Fecha de creación | `created_at`, formato ISO | `create`, formato `Y-m-d H:i:s` | | Otros campos | incluye `recurrent_id`, `updated_at` y `deleted_at` | no los incluye | Lo mismo pasa en [pagos de suscriptor](/developers/api/recurrentes/suscriptores/suscriptor-payments), que también usa `create` con formato `Y-m-d H:i:s`. ## Dos formas de decir "no configurado" [#no-configurado] En [listar planes](/developers/api/recurrentes/planes/get-plans), los campos de webhook de un plan vienen como cadena vacía cuando no están configurados, mientras que `return_url` viene como `null`. Son dos representaciones del mismo estado en el mismo objeto: al verificar si un webhook está configurado, tratá la cadena vacía y `null` como el mismo caso. ## `status` y `type` pueden venir como número o texto [#status-type] En las respuestas del API de adquirencia, `status` y `type` pueden ser números o cadenas. Por ejemplo, [crear cobros](/developers/api/cobros-tarjetas-guardadas/set-payments) devuelve `"status": 200` en el ejemplo exitoso y `"status": "400"` en el de error; [crear un grupo](/developers/api/cobros-tarjetas-guardadas/set-group) devuelve `"type": "200"`. Aceptá ambos tipos al leer estos indicadores; no asumas un único tipo para todas las operaciones. --- # Obtener token del API > Operación de login del API: devuelve el token bearer que firma el resto de las llamadas. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/autenticacion/token-api ```http POST /api/v1/login ``` ## Qué hace [#que-hace] Devuelve el token de seguridad necesario para consumir los servicios del API. El usuario y la contraseña de API se obtienen en [Panel administrativo · Integración con plataformas](https://admin.tilopay.com/platform-integrations). ## Autenticación [#autenticacion] No requiere token: es la operación que lo emite. Ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Usuario de API del comercio, obtenido en Panel administrativo · Integración con plataformas. Contraseña de API del comercio, obtenida en Panel administrativo · Integración con plataformas. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "apiuser": "", "password": "" } ``` ## Respuesta [#respuesta] ```json { "access_token": "", "token_type": "bearer", "expires_in": 86400 } ``` ## Respuestas de error [#respuestas-de-error] Credenciales inválidas → HTTP 401: ```json { "error": "Unauthorized" } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # Hosted payment page > Parámetros, ejemplo de request y respuesta de processPayment, la operación que abre el formulario de pago. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/hosted-payment-page/process-payment ```http POST /api/v1/processPayment ``` ## Qué hace [#que-hace] Devuelve la URL del formulario de pago para una compra. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Sitio donde esperás la respuesta de la transacción, por ejemplo `mywebsite.com`. Debe soportar el método **GET**. Ejemplo de respuesta al redirect: `mywebsite.com?code=1&description=Transaction%20is%20approved.&auth=123456&order=TPYS-881WROIBQA1405468&tpt=4300&crd=&tilopay-transaction=4300&OrderHash=b02927cb...&returnData=Tilopay-dataReturn123456789&form_update=ok`. Si `code = 1` la transacción está aprobada; en cualquier otro caso, rechazada. `OrderHash` es un string único por transacción: su algoritmo no es público y se solicita escribiendo a `soporte@tilopay.com`. Llave relacionada con el cliente. Se obtiene en Panel administrativo · Integración con plataformas. Monto de la compra. Moneda de la compra en formato ISO, por ejemplo USD, CRC, GTQ. Número de orden, puede ser alfanumérico. Captura y autoriza: 1 sí, 0 no. Nombre. Apellidos. Dirección. Dirección 2. Ciudad. Estado en formato ISO, por ejemplo CR-SJ (San José, Costa Rica) o US-CA (California, EE. UU.). Código postal. País en código ISO Alpha-2, por ejemplo CR (Costa Rica), US (EE. UU.) o GT (Guatemala). Teléfono. Correo del comprador. Nombre. Apellidos. Dirección. Dirección 2. Ciudad. Estado en formato ISO, por ejemplo CR-SJ (San José, Costa Rica) o US-CA (California, EE. UU.). Código postal. País en código ISO Alpha-2, por ejemplo CR (Costa Rica), US (EE. UU.) o GT (Guatemala). Teléfono. 1 para forzar que el cliente guarde la tarjeta en Tilopay, 0 para no. Nombre de la plataforma donde se genera la transacción. Valor que Tilopay devuelve en la respuesta final. Se recomienda enviar un string en base 64. Solo se usa al implementar la verificación de hash. Valores posibles [V1, V2]; por defecto V1. Enviar como valor "v2". ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "redirect": "https://www.urlToRedirect.com", "key": "", "amount": "1.00", "currency": "USD", "orderNumber": "1212122", "capture": "1", "billToFirstName": "DEMO", "billToLastName": "DEMO", "billToAddress": "San Jose", "billToAddress2": "Catedral", "billToCity": "JS", "billToState": "SJ", "billToZipPostCode": "10061", "billToCountry": "CR", "billToTelephone": "88888888", "billToEmail": "cliente@ejemplo.com", "shipToFirstName": "DEMO", "shipToLastName": "DEMO", "shipToAddress": "San Jose", "shipToAddress2": "Catedral", "shipToCity": "JS", "shipToState": "SJ", "shipToZipPostCode": "10061", "shipToCountry": "CR", "shipToTelephone": "88888888", "subscription": "0", "platform": "api", "returnData": "dXNlcl9pZD0xMg==", "hashVersion": "V2", "token_version": "v2" } ``` ## Respuesta [#respuesta] ```json { "type": "100", "html": "Use url redirect", "url": "https://secure.tilopay.com/htmls/1212122_574572148file.html" } ``` `"type": "100"` significa que se generó la URL del formulario: redirigí al cliente a `url` para que complete el pago. ## Parámetros que llegan al redirect [#parametros-del-redirect] Cuando el cliente termina el pago, Tilopay lo redirige a tu `redirect` con estos parámetros en la URL: | Parámetro | Qué es | |---|---| | `code` | `1` = transacción aprobada; cualquier otro valor = rechazada | | `description` | Texto del resultado | | `auth` | Código de autorización | | `order` | El `orderNumber` que enviaste | | `tpt` y `tilopay-transaction` | Id de la transacción en Tilopay | | `OrderHash` | Hash único de la transacción | | `returnData` | El valor que enviaste en el request | Antes de entregar el producto o liberar el servicio, confirmá el estado de la transacción con `POST /api/v1/consult` desde tu servidor — ver [consult](/developers/api/procesos-operativos/consult). ## Respuestas de error [#respuestas-de-error] HTTP 300: ```json { "type": "300", "message": "Message error" } ``` HTTP 400: ```json { "type": "400", "message": "Message error" } ``` HTTP 402: ```json { "type": "402", "message": "Message error" } ``` HTTP 403: ```json { "type": "403", "message": "Message error" } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # Servidor a servidor > Servicio exclusivo para comercios con certificación PCI. La URL se provisiona por comercio: no es autoservicio. - kind: guide - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/server-to-server > **Advertencia:** Acceso restringido. No es un camino de autoservicio. No podés empezar esta integración hoy > por tu cuenta: requiere que tu empresa tenga certificación PCI y una URL provisionada individualmente > por Tilopay. ## Qué es [#que-es] El camino en el que los datos de tarjeta pasan por tu servidor y este los envía al API de Tilopay. ## Para quién es [#para-quien] - Es un **servicio exclusivo para comercios que cuentan con certificación PCI**. - La **URL es personalizada por comercio**, con una llave propia. **No es una URL pública.** Por eso los ejemplos de esta página no traen una URL real: el `Host` y la llave del proxy se entregan a cada comercio aprobado. ## Requisitos [#requisitos] 1. Certificación PCI vigente de tu empresa. 2. Cuenta Tilopay activa. 3. Solicitud aprobada, con la URL y la llave provisionadas por Tilopay para tu comercio. ## Cómo se solicita [#solicitud] Escribí a `soporte@tilopay.com` con el nombre de tu comercio y el estado de tu certificación PCI. La URL y la llave se entregan directamente al comercio aprobado. ## Referencia de la petición [#referencia] > **Advertencia:** El `Host` y el header `tx-proxy-key` los entrega Tilopay a cada comercio aprobado. No hay una URL > pública: los ejemplos usan marcadores. ```http POST / HTTP/1.1 Host: url provided by tilopay ``` ### Encabezados [#encabezados] `bearer {token del API}` — ver [autenticación](/developers/api/autenticacion). Llave del proxy de transacciones, provista por Tilopay. ### Parámetros [#parametros] Llave relacionada con el comercio (obligatorio). Número de tarjeta (obligatorio). Código de seguridad (obligatorio). Fecha de expiración en formato mesAño, por ejemplo `1023` (obligatorio). Nombre del tarjetahabiente (requerido). Apellidos del tarjetahabiente (requerido). Teléfono del cliente (requerido). Correo del cliente (obligatorio). Dirección del cliente (requerido). Ciudad del cliente (requerido). Estado en formato ISO, por ejemplo `CR-SJ` (San José, Costa Rica) o `US-CA` (California, EEUU) (requerido). Código postal (requerido). País en código ISO Alpha-2, por ejemplo `CR`, `US`, `GT` (requerido). Monto de la compra (obligatorio). Moneda en formato ISO, por ejemplo `USD`, `CRC`, `GTQ` (obligatorio). Número de orden (obligatorio). `1` captura y autoriza, `0` solo autoriza (obligatorio). URL de respuesta (obligatorio). Datos de envío opcionales: `shipToFirstName`, `shipToLastName`, `shipToAddress`, `shipToAddress2`, `shipToCity`, `shipToState`, `shipToZipPostCode`, `shipToCountry`, `shipToTelephone`. ### Petición [#peticion] ```json { "key": "key", "card": "card PAN", "cvv": "CVV Number", "expire": "1023", "name": "firstname", "lastname": "lastname", "phone": "88888888", "email": "email@user.com", "address": "user address", "city": "city", "state": "state", "zipcode": "zipcode", "country": "country", "shipToFirstName": "Nombre", "shipToLastName": "Apellido", "shipToAddress": "San Jose", "shipToAddress2": "Escazu", "shipToCity": "San Jose", "shipToState": "SJ", "shipToZipPostCode": "10101", "shipToCountry": "CR", "shipToTelephone": "88778877", "amount": "amount", "currency": "currency code", "orderNumber": "Order Number", "capture": 1, "redirect": "url to redirect" } ``` La colección incluye dos ejemplos, **con 3DS** y **sin 3DS**, con el mismo cuerpo de petición. ### Respuesta [#respuesta] Sin 3DS: ```json { "code": "1", "description": "Transaccion aprobada", "auth": "123456", "orderNumber": "12345", "urlRedirect": "", "error": "" } ``` Con 3DS: ```json { "code": "", "description": "", "auth": "", "orderNumber": "12457", "urlRedirect": "https://secure.tilopay.com/htmls/1026345966.html", "error": "" } ``` Cuando la transacción requiere autenticación 3DS, la respuesta trae la URL en `urlRedirect`; ahí es donde se envía al tarjetahabiente. Para interpretar `code`, `description` y `error`, ver [convenciones de las respuestas](/developers/api/convenciones) y [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). ## Alternativas sin certificación PCI [#alternativas] Si no tenés certificación PCI, estos caminos evitan por completo ese alcance: - [Hosted payment page](/developers/hosted-payment-page) — Tilopay hospeda el formulario. - [SDK JavaScript](/developers/sdk) — el formulario vive en tu página, pero los datos viajan del navegador directo a Tilopay. - [Sin código](/developers/sin-codigo) — plugin o plataforma ya integrada. --- # Links de pago > Operaciones de links de pago del API de Tilopay, con parámetros y ejemplos. - kind: api-index - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/links-de-pago ## Operaciones [#operaciones] - [Crear link de pago](/developers/api/links-de-pago/create-link-payment) - [Detalle de un link de pago](/developers/api/links-de-pago/detail-link-payment) - [Eliminar un link de pago](/developers/api/links-de-pago/delete-link-payment) - [Listar links de pago](/developers/api/links-de-pago/payment-item-list) - [Obtener un link de pago por id](/developers/api/links-de-pago/payment-by-id) Todas las operaciones viven en `https://app.tilopay.com` y, salvo las de login, requieren el token del API — ver [autenticación](/developers/api/autenticacion). --- # API · Crear link de pago > Creación de links de pago por API, con callback y webhook de respuesta. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/links-de-pago/create-link-payment ```http POST /api/v1/createLinkPayment ``` ## Qué hace [#que-hace] Crea un link de pago con monto, moneda y comportamiento de uso. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Monto para el link de pago. Código de moneda en formato ISO 4217. Referencia del link de pago. Tipo de link: 0 ilimitado, 1 de un solo uso. Descripción del pago. Nombre del cliente, aplica solo cuando type es 1. Campo opcional. URL, por método **GET**, a la que se redirige con la respuesta al completar el pago. Ejemplo de los datos enviados: `code=Val&description=Val&auth=Val&tilopayLinkId=Val&orderNumber=Val&tilopayOrderId=Val&creditCardToken=Val&creditCardBrand=Val&last4CreditCardNumber=Val&orderHash=Val` Campo opcional. URL para enviar el webhook de respuesta al completar el pago. Debe ser de método **POST** para que reciba los datos. Ejemplo de los datos enviados: ```json { "code": "1", "codeDescription": "Aprobada", "auth": "123456", "tilopayLinkId": 54421, "orderNumber": "TPT123", "tilopayOrderId": 12233, "creditCardToken": "41111******11111", "creditCardBrand": "Visa", "last4CreditCardNumber": "1111", "linkDescription": "Descripcion del link de pago", "orderHash": "" } ``` ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "amount": "10", "currency": "USD", "reference": "123456", "type": 0, "description": "Description", "client": "Client name", "callback_url": "", "webhook_url": "" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "message": "Success", "url": "https://app.tilopay.com/link/MjMwMjQ=", "id": 1 } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Detalle de un link de pago > Detalle de un link de pago y sus pagos, consultado por id. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/links-de-pago/detail-link-payment ```http GET /api/v1/getDetailLinkPayment/{link_payment_id}/{api_key} ``` ## Qué hace [#que-hace] Devuelve el detalle de un link de pago y sus pagos asociados. No lleva cuerpo: los datos van en la ruta. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Parámetros de ruta, en el orden en que aparecen en la URL: Id del link de pago a consultar. Api Key del comercio. ## Respuesta [#respuesta] ```json { "type": "200", "message": "Success", "detail": { "id": 6201, "amount": "45.00", "currency": "USD", "reference": "Producto de prueba 1 TP-Shop", "client": "NA", "type": "Unlimited", "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", "callback_url": null, "create": "2022-10-24 08:45:14" }, "payments": [] } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Eliminar un link de pago > Eliminación de un link de pago por id. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/links-de-pago/delete-link-payment ```http POST /api/v1/deleteLinkPayment ``` ## Qué hace [#que-hace] Elimina un link de pago existente. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Id del link de pago. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "id": "35" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "status": 1, "message": "Success" } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Listar links de pago > Listado paginado de los links de pago del comercio. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/links-de-pago/payment-item-list ```http GET /api/v1/getLinkPaymentList/{api_key}/{limit} ``` ## Qué hace [#que-hace] Devuelve la lista paginada de links de pago del comercio. No lleva cuerpo: los datos van en la ruta. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Parámetros de ruta, en el orden en que aparecen en la URL: Api Key del comercio. Cantidad de registros por página. ## Respuesta [#respuesta] ```json { "type": "200", "message": "Success", "data": { "current_page": 1, "first_page_url": "http://app.tilopay.com/api/v1/getLinkPaymentList//10?page=1", "from": 1, "last_page": 2, "last_page_url": "http://app.tilopay.com/api/v1/getLinkPaymentList//10?page=2", "next_page_url": "http://app.tilopay.com/api/v1/getLinkPaymentList//10?page=2", "path": "http://app.tilopay.com/api/v1/getLinkPaymentList//10", "per_page": 10, "prev_page_url": null, "to": 10, "total": 16, "payment_link": [ { "id": 1, "amount": "45.00", "currency": "USD", "reference": "Producto de prueba 1 TP-Shop", "url": "https://admin.tilopay.com/link/3dNjE2MA3sdd==", "callback_url": null, "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", "times_used": null, "picture": "https://storage.googleapis.com/tilo-uploads/items/51087219_.png", "create": "2022-10-24 08:45:14" }, { "id": 2, "amount": "35.00", "currency": "USD", "reference": "Producto de prueba 2", "url": "https://admin.tilopay.com/link/dwNjE2see3MA==", "callback_url": null, "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", "times_used": null, "picture": "https://storage.googleapis.com/tilo-uploads/items/64156766_.png", "create": "2022-10-24 08:45:14" }, { "id": 3, "amount": "45.00", "currency": "USD", "reference": "Producto de prueba 3", "url": "https://admin.tilopay.com/link/f4NjE2MwsdA==", "callback_url": null, "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", "times_used": null, "picture": "https://storage.googleapis.com/tilo-uploads/items/88435879_.png", "create": "2022-10-24 08:45:14" }, { "id": 4, "amount": "45.00", "currency": "USD", "reference": "test", "url": "https://admin.tilopay.com/link/ceNjE2sxw2MA==", "callback_url": null, "description": "ddd", "times_used": null, "picture": "https://storage.googleapis.com/tilo-uploads/items/37716065_.png", "create": "2022-10-24 08:45:14" }, { "id": 5, "amount": "45.00", "currency": "USD", "reference": "test", "url": "https://admin.tilopay.com/link/cweNjE2Mfd5A==", "callback_url": null, "description": "ddd", "times_used": null, "picture": "https://storage.googleapis.com/tilo-uploads/items/37716065_.png", "create": "2022-10-24 08:45:14" }, { "id": 6, "amount": "45.00", "currency": "USD", "reference": "test", "url": "https://admin.tilopay.com/link/ce3NjE2fg5eMA==", "callback_url": null, "description": "ddd", "times_used": null, "picture": "https://storage.googleapis.com/tilo-uploads/items/37716065_.png", "create": "2022-10-24 08:45:14" }, { "id": 7, "amount": "45.00", "currency": "USD", "reference": "test", "url": "https://admin.tilopay.com/link/dsNjE2MAd32==", "callback_url": null, "description": "ddd", "times_used": null, "picture": "https://storage.googleapis.com/tilo-uploads/items/37716065_.png", "create": "2022-10-24 08:45:14" }, { "id": 8, "amount": "45.00", "currency": "USD", "reference": "test", "url": "https://admin.tilopay.com/link/NjE2sd32MA==", "callback_url": null, "description": "ddd", "times_used": null, "picture": "https://storage.googleapis.com/tilo-uploads/items/37716065_.png", "create": "2022-10-24 08:45:14" }, { "id": 9, "amount": "45.00", "currency": "USD", "reference": "test", "url": "https://admin.tilopay.com/link/sd3NjE2MA==", "callback_url": null, "description": "ddd", "times_used": null, "picture": "https://storage.googleapis.com/tilo-uploads/items/37716065_.png", "create": "2022-10-24 08:45:14" }, { "id": 10, "amount": "45.00", "currency": "USD", "reference": "test", "url": "https://admin.tilopay.com/link/d3dNjE2MA==", "callback_url": null, "description": "ddd", "times_used": null, "picture": "https://storage.googleapis.com/tilo-uploads/items/37716065_.png", "create": "2022-10-24 08:45:14" } ] } } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Obtener un link de pago por id > Consulta de un link de pago puntual por su id. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/links-de-pago/payment-by-id ```http GET /api/v1/getLinkPaymentById/{link_payment_id}/{api_key} ``` ## Qué hace [#que-hace] Devuelve un link de pago puntual. No lleva cuerpo: los datos van en la ruta. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Parámetros de ruta, en el orden en que aparecen en la URL: Id del link de pago a consultar. Api Key del comercio. ## Respuesta [#respuesta] ```json { "type": "200", "message": "Success", "data": { "id": 1, "amount": "45.00", "currency": "USD", "reference": "Producto de prueba 1 TP-Shop", "url": "https://admin.tilopay.com/link/loNj8E2MA==", "callback_url": null, "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", "times_used": null, "picture": "https://storage.googleapis.com/tilo-uploads/items/51087219_.png", "create": "2022-10-24 08:45:14", "payments": [] } } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # Cobros Recurrentes > Operaciones de cobros recurrentes del API de Tilopay, con parámetros y ejemplos. - kind: api-index - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/recurrentes ## Operaciones [#operaciones] 16 operaciones en tres subgrupos: - [Planes](/developers/api/recurrentes/planes) — 5 - [Suscriptores](/developers/api/recurrentes/suscriptores) — 7 - [Cupones](/developers/api/recurrentes/cupones) — 4 Todas las operaciones viven en `https://app.tilopay.com` y, salvo las de login, requieren el token del API — ver [autenticación](/developers/api/autenticacion). --- # API · Recurrentes · Planes > Operaciones de recurrentes · planes del API de Tilopay, con parámetros y ejemplos. - kind: api-index - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/recurrentes/planes ## Operaciones [#operaciones] - [Crear plan recurrente](/developers/api/recurrentes/planes/create-plan) - [Editar plan recurrente](/developers/api/recurrentes/planes/edit-plan) - [Obtener un plan recurrente](/developers/api/recurrentes/planes/get-plan) - [Listar planes recurrentes](/developers/api/recurrentes/planes/get-plans) - [Eliminar plan recurrente](/developers/api/recurrentes/planes/delete-plan) Todas las operaciones viven en `https://app.tilopay.com` y, salvo las de login, requieren el token del API — ver [autenticación](/developers/api/autenticacion). --- # API · Crear plan recurrente > Creación de planes recurrentes: frecuencias, prueba gratis, modalidades y webhooks. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/api/recurrentes/planes/create-plan ```http POST /api/v1/createPlanRepeat ``` ## Qué hace [#que-hace] Crea un plan de suscripción: frecuencia de cobro, moneda, periodo de prueba, modalidades y webhooks. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Título del plan recurrente. Descripción del plan. Frecuencia de cobro. | Código | Valor | | --- | --- | | 1 | Diario | | 2 | Semanal | | 3 | Mensual | | 4 | Anual | | 5 | Quincenal | | 6 | Bimestral | | 7 | Trimestral | | 8 | Cuatrimestral | | 9 | Semestral | Código de moneda en formato ISO 4217. Monto por pago inicial. Activa el periodo de prueba gratis: 0 no, 1 sí. Días del periodo de prueba gratis. Cantidad de reintentos para cobros fallidos. Array de modalidades del plan. Campo opcional. URL de agradecimiento propia del comercio; debe soportar el método **GET**. Campo opcional. URL del webhook, por método **POST**, que recibe el callback en el cuerpo de la solicitud cuando un cliente adquiere una suscripción de forma exitosa. Ejemplo de los datos enviados: `{'id_plan' : 1, 'email' : 'email@email.com', 'modality' : 'ModalityName', 'amount' : 25, 'frequency' : '', 'coupon' : '5HT5W8YT', 'free_trial' : 1, 'next_payment_date' : '2023-02-25'}` Campo opcional. URL del webhook, por método **POST**, que recibe el callback en el cuerpo de la solicitud cuando el cargo al cliente se realiza con éxito. Ejemplo de los datos enviados: `{'id_plan' : 1, 'email' : 'email@email.com', 'amount' : 25, 'auth' : '123456', 'orderNumber' : 'PRE123456'}` Campo opcional. URL del webhook, por método **POST**, que recibe el callback en el cuerpo de la solicitud cuando un pago falla. Ejemplo de los datos enviados: `{'id_plan' : 1, 'email' : 'email@email.com', 'amount' : 25}` Campo opcional. URL del webhook, por método **POST**, que recibe el callback en el cuerpo de la solicitud cuando un cliente cancela la suscripción a uno de sus planes. Ejemplo de los datos enviados: `{'id_plan' : 1, 'email' : 'email@email.com', 'expire' : '2023-02-25'}` Campo opcional. URL del webhook, por método **POST**, que recibe el callback en el cuerpo de la solicitud cuando un cliente reactiva la suscripción a uno de sus planes. Ejemplo de los datos enviados: `{'id_plan' : 1, 'email' : 'email@email.com', 'next_payment_date' : '2023-02-25'}` Fecha de finalización del plan recurrente, formato `d-m-Y` (por ejemplo 25-09-2022). Si el plan no tiene fecha de fin, se envía vacío. En 1 agrega al correo de notificación el texto de `notify_detail` y `notify_note`. En 0 no agrega ninguno de los dos. Texto del detalle en español. Opcional si `notify` es 0. Texto del detalle en inglés. Opcional si `notify` es 0. Texto de las notas en español. Opcional si `notify` es 0. Texto de las notas en inglés. Opcional si `notify` es 0. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "title": "Plan title", "description": "Plan description", "frecuency": 1, "currency": "USD", "first_amount": 0, "trial": 0, "trial_days": 0, "attempts": 1, "modality": [ { "title": "Basic", "amount": 10 }, { "title": "Premium", "amount": 30 } ], "thanks_url": "", "webhook_subscribe": "", "webhook_payment": "", "webhook_rejected": "", "webhook_unsubscribe": "", "webhook_reactive": "", "end_at": "25-10-2023", "notify": 0, "notify_detail_es": "", "notify_detail_en": "", "notify_note_es": "", "notify_note_en": "" } ``` ## Respuesta [#respuesta] URL del plan en `https://tp.cr` o `https://app.tilopay.com`. ```json { "type": "200", "status": 1, "message": "Success", "id": 624, "url": "https://app.tilopay.com/link/TmpJMHwx" } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Editar plan recurrente > Edición de un plan recurrente y de su estado. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/api/recurrentes/planes/edit-plan ```http POST /api/v1/editPlanRepeat ``` ## Qué hace [#que-hace] Edita un plan existente, incluido su estado. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Id del plan recurrente. Título del plan recurrente. Descripción del plan. Frecuencia de cobro. | Código | Valor | | --- | --- | | 1 | Diario | | 2 | Semanal | | 3 | Mensual | | 4 | Anual | | 5 | Quincenal | | 6 | Bimestral | | 7 | Trimestral | | 8 | Cuatrimestral | | 9 | Semestral | Código de moneda en formato ISO 4217. Monto por pago inicial. Activa el periodo de prueba gratis: 0 no, 1 sí. Días del periodo de prueba gratis. Cantidad de reintentos para cobros fallidos. Estado del plan recurrente. | Código | Valor | | --- | --- | | 0 | Inactivo | | 1 | Activo | | 2 | Activo pero sin registros nuevos | Campo opcional. URL de agradecimiento propia del comercio; debe soportar el método **GET**. Campo opcional. URL del webhook, por método **POST**, que recibe el callback en el cuerpo de la solicitud cuando un cliente adquiere una suscripción de forma exitosa. Ejemplo de los datos enviados: `{'id_plan' : 1, 'email' : 'email@email.com', 'modality' : 'ModalityName', 'amount' : 25, 'frequency' : '', 'coupon' : '5HT5W8YT', 'free_trial' : 1, 'next_payment_date' : '2023-02-25'}` Campo opcional. URL del webhook, por método **POST**, que recibe el callback en el cuerpo de la solicitud cuando el cargo al cliente se realiza con éxito. Ejemplo de los datos enviados: `{'id_plan' : 1, 'email' : 'email@email.com', 'amount' : 25, 'auth' : '123456', 'orderNumber' : 'PRE123456'}` Campo opcional. URL del webhook, por método **POST**, que recibe el callback en el cuerpo de la solicitud cuando un pago falla. Ejemplo de los datos enviados: `{'id_plan' : 1, 'email' : 'email@email.com', 'amount' : 25}` Campo opcional. URL del webhook, por método **POST**, que recibe el callback en el cuerpo de la solicitud cuando un cliente cancela la suscripción a uno de sus planes. Ejemplo de los datos enviados: `{'id_plan' : 1, 'email' : 'email@email.com', 'expire' : '2023-02-25'}` Campo opcional. URL del webhook, por método **POST**, que recibe el callback en el cuerpo de la solicitud cuando un cliente reactiva la suscripción a uno de sus planes. Ejemplo de los datos enviados: `{'id_plan' : 1, 'email' : 'email@email.com', 'next_payment_date' : '2023-02-25'}` Fecha de finalización del plan recurrente, formato `d-m-Y` (por ejemplo 25-09-2022). Si el plan no tiene fecha de fin, se envía vacío. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "id": 3, "title": "Plan title", "description": "Plan description", "frecuency": 2, "currency": "USD", "first_amount": 0, "trial": 0, "trial_days": 0, "attempts": 5, "status": 1, "thanks_url": "", "webhook_subscribe": "", "webhook_payment": "", "webhook_rejected": "", "webhook_unsubscribe": "", "webhook_reactive": "", "end_at": "25-10-2023" } ``` ## Respuesta [#respuesta] URL del plan en `https://tp.cr` o `https://app.tilopay.com`. ```json { "type": "200", "status": 1, "message": "Success", "url": "https://app.tilopay.com/link/" } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Obtener un plan recurrente > Consulta de un plan recurrente por id. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/recurrentes/planes/get-plan ```http POST /api/v1/getPlanRepeat ``` ## Qué hace [#que-hace] Devuelve un plan recurrente puntual. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Id del plan recurrente. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "id": "3" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "message": "Success", "plan": { "id": 232, "title": "Prueba repeat", "description": "Plan repeat de prueba mensual", "frequency": 3, "currency": "USD", "first_amount": "5.00", "trial": 0, "trial_days": 0, "attempts": 5, "thanks_url": null, "webhook_subscribe": null, "webhook_payment": null, "webhook_rejected": null, "webhook_unsubscribe": null, "webhook_reactive": null, "modality": [ { "id": 292, "title": "Pago mensual prueba repeat modalidad", "amount": "10.00" } ], "end_at": null } } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Listar planes recurrentes > Listado de los planes recurrentes de la integración. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/recurrentes/planes/get-plans ```http POST /api/v1/getPlansRepeat ``` ## Qué hace [#que-hace] Devuelve los planes recurrentes del comercio. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "message": "Success", "data": [ { "id": 276, "title": "Plan test 1", "description": "Plan", "frequency": 1, "currency": "USD", "first_amount": "0.00", "trial": 0, "trial_days": 0, "attempts": 1, "status": 1, "thanks_url": "", "return_url": null, "webhook_subscribe": "", "webhook_payment": "", "webhook_rejected": "", "webhook_unsubscribe": "", "webhook_reactive": "", "modality": [ { "id": 131, "title": "Basic", "amount": "10.00" } ], "end_at": "2022-10-25" } ] } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Eliminar plan recurrente > Eliminación de un plan recurrente por id. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/recurrentes/planes/delete-plan ```http POST /api/v1/deletePlanRepeat ``` ## Qué hace [#que-hace] Elimina un plan recurrente. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Id del plan recurrente. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "id": "625" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "status": 1, "message": "Success" } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Recurrentes · Suscriptores > Operaciones de recurrentes · suscriptores del API de Tilopay, con parámetros y ejemplos. - kind: api-index - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/recurrentes/suscriptores ## Operaciones [#operaciones] - [Suscriptores de un plan](/developers/api/recurrentes/suscriptores/get-suscriptor-plan) - [Editar suscriptor](/developers/api/recurrentes/suscriptores/edit-suscriptor-plan) - [Pausar suscriptor](/developers/api/recurrentes/suscriptores/pause-suscriptor-plan) - [Reactivar suscriptor](/developers/api/recurrentes/suscriptores/reactive-suscriptor-plan) - [Eliminar suscriptor](/developers/api/recurrentes/suscriptores/delete-suscriptor-plan) - [URL de registro y renovación](/developers/api/recurrentes/suscriptores/consult-url) - [Pagos de suscriptor](/developers/api/recurrentes/suscriptores/suscriptor-payments) Todas las operaciones viven en `https://app.tilopay.com` y, salvo las de login, requieren el token del API — ver [autenticación](/developers/api/autenticacion). --- # API · Suscriptores de un plan > Consulta de los suscriptores de un plan recurrente. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/recurrentes/suscriptores/get-suscriptor-plan ```http POST /api/v1/getSuscriptorRepeat ``` ## Qué hace [#que-hace] Devuelve los suscriptores asociados a un plan recurrente. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Id del plan recurrente. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "id": "2" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "message": "Success", "suscriptor": [ { "id": 360, "name": "Jhon 1", "lastname": "D", "email": "customer1@example.com", "modality": "Pago mensual prueba repeat modalidad", "amount": "10.00", "expire": "2023-03-26", "coupon": "", "status": "Delete", "create": "2022-10-19 12:48:59" }, { "id": 33364, "name": "Jhon 2", "lastname": "D", "email": "customer2@example.com", "modality": "Pago mensual prueba repeat modalidad", "amount": "10.00", "expire": "2023-08-05", "coupon": "", "status": "Active", "create": "2023-06-05 14:24:18" } ] } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Editar suscriptor > Edición del estado y la expiración de un suscriptor. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/recurrentes/suscriptores/edit-suscriptor-plan ```http POST /api/v1/editSuscriptorRepeat ``` ## Qué hace [#que-hace] Cambia el estado o la fecha de expiración de un suscriptor. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Id del suscriptor. Estado del suscriptor. | Código | Valor | | --- | --- | | 1 | Activo | | 3 | Pausado | | 4 | Eliminado | Fecha de expiración del plan, formato `Y-m-d` (por ejemplo 2023-10-25). ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "id": "2", "status": "3", "expire": "2023-10-25" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "status": 1, "message": "Success" } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Pausar suscriptor > Pausa de la suscripción de un suscriptor. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/recurrentes/suscriptores/pause-suscriptor-plan ```http POST /api/v1/pauseSuscriptorRepeat ``` ## Qué hace [#que-hace] Pausa la suscripción de un suscriptor. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Id del suscriptor. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "id_suscriptor": "1" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "status": 1, "message": "Success" } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Reactivar suscriptor > Reactivación de la suscripción de un suscriptor. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/recurrentes/suscriptores/reactive-suscriptor-plan ```http POST /api/v1/reactiveSuscriptorRepeat ``` ## Qué hace [#que-hace] Reactiva la suscripción de un suscriptor pausado. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Id del suscriptor. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "id_suscriptor": "1" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "status": 1, "message": "Success" } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Eliminar suscriptor > Eliminación de un suscriptor de un plan recurrente. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/recurrentes/suscriptores/delete-suscriptor-plan ```http POST /api/v1/deleteSuscriptorRepeat ``` ## Qué hace [#que-hace] Elimina un suscriptor de un plan recurrente. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Id del suscriptor. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "id_suscriptor": "1" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "status": 1, "message": "Success" } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · URL de registro y renovación > URL de registro o renovación de un plan recurrente para un correo dado. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/recurrentes/suscriptores/consult-url ```http POST /api/v1/recurrentUrl ``` ## Qué hace [#que-hace] Devuelve la URL de registro de un plan recurrente para un usuario nuevo, o la URL de renovación si el correo ya está registrado. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Id del plan recurrente. Correo del usuario para el que se quiere crear el link de registro. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "id": "1", "email": "email@user.com" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "message": "", "url_register": "https://app.tilopay.com/admin/recurrent/register/MjMy?email=email@user.com", "url_renew": "" } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Pagos de suscriptor > Historial de pagos de los suscriptores de un plan recurrente. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/recurrentes/suscriptores/suscriptor-payments ```http POST /api/v1/getSuscriptorPayments ``` ## Qué hace [#que-hace] Devuelve los pagos de los suscriptores de un plan recurrente. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Id del plan recurrente. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "id": "1" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "message": "Success", "data": [ { "id": 150, "commerce_id": 37, "suscriptor_id": 86, "reference": "0", "currency": "USD", "amount": "0.00", "status": 0, "data": "{\"first\":1,\"expire\":\"2024-12-28T19:05:29.572648Z\",\"amount\":0,\"activeAmount\":0,\"originalAmount\":0,\"key\":\"XXXX-XXXX-XXXX-XXXX-XXXX\"}", "create": "2024-12-13 13:05:06" } ] } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Recurrentes · Cupones > Operaciones de recurrentes · cupones del API de Tilopay, con parámetros y ejemplos. - kind: api-index - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/recurrentes/cupones ## Operaciones [#operaciones] - [Crear cupón](/developers/api/recurrentes/cupones/create-coupon) - [Listar cupones de un plan](/developers/api/recurrentes/cupones/get-coupons) - [Obtener un cupón](/developers/api/recurrentes/cupones/get-coupon) - [Eliminar cupón](/developers/api/recurrentes/cupones/delete-coupon) Todas las operaciones viven en `https://app.tilopay.com` y, salvo las de login, requieren el token del API — ver [autenticación](/developers/api/autenticacion). --- # API · Crear cupón > Creación de cupones de descuento para planes recurrentes. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/recurrentes/cupones/create-coupon ```http POST /api/v1/createCoupon ``` ## Qué hace [#que-hace] Crea un cupón de descuento para un plan recurrente: tipo de descuento, expiración, permisos de usuario y de correo, y límites de uso. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Id del plan recurrente. Permiso de usuarios. | Código | Valor | | --- | --- | | 0 | Permitir solo usuarios nuevos | | 1 | Permitir usuarios ya registrados | Tipo de descuento. | Código | Valor | | --- | --- | | 1 | Porcentaje | | 2 | Monto fijo | Valor numérico del descuento. Fecha de expiración del cupón, formato `Y-m-d` (por ejemplo 2025-10-20). Permiso de correos. | Código | Valor | | --- | --- | | 1 | Correos específicos | | 2 | Cualquier correo | Lista de correos separados por coma. Requerido si `email_group` se envía en 1. Cantidad total de usos. Cantidad total de renovaciones válidas. Total de usos por un mismo usuario. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "planId": 10, "active_users": 1, "type_discount": 1, "discount": 40, "expire": "2025-10-20", "email_group": 1, "email": "cliente@ejemplo.com, cliente@ejemplo.com", "usage": 1, "renews": 2, "renews_by_user": 2 } ``` ## Respuesta [#respuesta] ```json { "type": "200", "status": 1, "message": "Success", "id": 10788, "code": "E6RMS339" } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Listar cupones de un plan > Listado de los cupones de un plan recurrente. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/recurrentes/cupones/get-coupons ```http POST /api/v1/getRepeatCoupons ``` ## Qué hace [#que-hace] Devuelve los cupones asociados a un plan recurrente. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Id del plan recurrente. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "id": "1" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "message": "Success", "data": [ { "id": 10787, "code": "TK7DPCHY", "active_users": 1, "type_discount": 1, "discount": "30.00", "expire": "2026-06-12", "email_group": 2, "email": null, "usage": 1, "renews": 1, "renews_by_user": 1, "usage_counter": 0, "create": "2026-06-12 15:17:34" } ] } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Obtener un cupón > Consulta de un cupón recurrente por id. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/recurrentes/cupones/get-coupon ```http POST /api/v1/getCoupon ``` ## Qué hace [#que-hace] Devuelve un cupón puntual. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Id del cupón. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "id": "1" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "message": "Success", "data": { "id": 10788, "recurrent_id": 10, "code": "E6RMS339", "active_users": 1, "type_discount": 1, "discount": "40.00", "expire": "2026-10-20", "email_group": 1, "email": "cliente@ejemplo.com, otro@ejemplo.com", "usage": 1, "renews": 2, "renews_by_user": 2, "usage_counter": 0, "created_at": "2026-09-02T20:12:01.000000Z", "updated_at": "2026-09-02T20:12:01.000000Z", "deleted_at": null } } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Eliminar cupón > Eliminación de un cupón recurrente por id. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/recurrentes/cupones/delete-coupon ```http POST /api/v1/deleteCoupon ``` ## Qué hace [#que-hace] Elimina un cupón. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Id del cupón. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "id": "1" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "status": 1, "message": "Success" } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # Credential on File (CoF) > Operaciones de credential on file (cof) del API de Tilopay, con parámetros y ejemplos. - kind: api-index - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/cof ## Operaciones [#operaciones] 3 operaciones: - [Tokenizar tarjeta](/developers/api/cof/process-tokenize) — 1 - [Eliminar tarjeta](/developers/api/cof/remove-card) — 1 - [Realizar cobro](/developers/api/cof/realizar-cobro) — 1 Todas las operaciones viven en `https://app.tilopay.com` y, salvo las de login, requieren el token del API — ver [autenticación](/developers/api/autenticacion). --- # API · Crear CoF (Tokenizar) > Tokenización de tarjeta con processTokenize: parámetros, request y respuesta. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/api/cof/process-tokenize ```http POST /api/v1/processTokenize ``` ## Qué hace [#que-hace] Tokeniza una tarjeta: devuelve la URL del formulario de tokenización. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Sitio donde espera la respuesta de la transacción. Key asociado al comercio. Correo electrónico del tarjetahabiente. Idioma [es, en]. Nombre del tarjetahabiente. Apellido del tarjetahabiente. Enviar como valor "v2". ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "redirect": "https://urlToRedirect.com", "key": "", "email": "email@user.com", "language": "es", "firstname": "name", "lastname": "lastname", "token_version": "v2" } ``` ## Respuesta [#respuesta] ```json { "type": "100", "url": "https://secure.tilopay.com/htmls/TOK-5063-740506121440_1648145457file.html" } ``` ## Respuestas de error [#respuestas-de-error] ## Parámetros que llegan al redirect [#parametros-del-redirect] `token`, `code`, `description`, `auth`, `crd`, `order`, `tpt`, `brand`, `last-digits`, `tilopay-transaction`, `OrderHash`, `returnData`. El token de la tarjeta viaja en `token` y `crd`; guardalo asociado al correo del cliente. `brand` y `last-digits` sirven para mostrar la tarjeta guardada. `crd` solo trae valor cuando la tarjeta quedó guardada con `code = 1`. HTTP 300: ```json { "type": "300", "result": "Message error" } ``` HTTP 402: ```json { "type": "402", "result": "Message error" } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Eliminar CoF > Eliminación de un token de tarjeta guardado en la bóveda privada del comercio. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/cof/remove-card ```http POST /api/v1/user/card-remove ``` ## Qué hace [#que-hace] Elimina un token de tarjeta guardado. **Requisito:** el comercio debe contar con una bóveda de tokens privada. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Llave relacionada con el comercio. Correo del cliente asociado al token. Token a eliminar. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "1234-1234-1234-1234-1234", "email": "email@card.com", "token": "411111.......1111" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "status": 1, "message": "Success" } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Realizar cobro CoF > Cobro servidor a servidor con token de tarjeta v2 mediante Credential on File. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/cof/realizar-cobro ```http POST /api/v1/processRecurrentPayment ``` ## Qué hace [#que-hace] Procesa un cobro con una tarjeta ya tokenizada, sin formulario. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Llave relacionada con el cliente. Se obtiene en Panel administrativo · Integración con plataformas. Monto de la compra. Moneda de la compra en formato ISO, por ejemplo USD, CRC, GTQ. Número de orden, puede ser alfanumérico. Captura y autoriza: 1 sí, 0 no. Correo del tarjetahabiente. Token de tarjeta, debe ser el token v2. Solo si implementás la verificación de hash. Valores V1 o V2; por defecto V1. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "amount": "10.00", "currency": "USD", "orderNumber": "1213", "capture": "1", "email": "myemail@exapmle.com", "card": "511111_00GOB1111" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "response": "1", "description": "Transacción aprobada", "auth": "123456", "tpt": 734329, "order_id": "12135", "tilopayTransaction": 734329, "orderHash": "f3ad85046d249bc7a781eed5285a5ded92045a2e11108063504deec72ec9b338" } ``` ## Respuestas de error [#respuestas-de-error] HTTP 300: ```json { "type": "300", "result": "Message error" } ``` HTTP 400: ```json { "type": "400", "result": "Message error" } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # Procesos operativos > Operaciones de procesos operativos del API de Tilopay, con parámetros y ejemplos. - kind: api-index - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/procesos-operativos ## Operaciones [#operaciones] - [processModification](/developers/api/procesos-operativos/process-modification) - [consult](/developers/api/procesos-operativos/consult) - [consultTransactions](/developers/api/procesos-operativos/consult-transactions) - [Dividir liquidación (split)](/developers/api/procesos-operativos/split) Estas operaciones son transversales: sirven para cualquiera de los cuatro [caminos de integración](/developers), sin importar cómo se originó el cobro. Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). Todas las operaciones viven en `https://app.tilopay.com` y, salvo las de login, requieren el token del API — ver [autenticación](/developers/api/autenticacion). --- # API · processModification > Captura, reembolso y reverso de una transacción con processModification. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/api/procesos-operativos/process-modification ```http POST /api/v1/processModification ``` ## Qué hace [#que-hace] Permite modificar una transacción ya procesada: captura, reembolso o reverso. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Número de la orden que se envió en el cobro original. Tipo de modificación. | Código | Valor | | --- | --- | | 1 | Captura | | 2 | Reembolso | | 3 | Reverso | Monto que se desea modificar. Llave relacionada con el cliente. Se obtiene en Panel administrativo · Integración con plataformas. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "orderNumber": "1214352", "type": "2", "amount": "1.00", "key": "" } ``` ## Respuesta [#respuesta-modificacion] `type: "100"` indica que la modificación se procesó; el resultado está en `ReasonCode` y `ReasonCodeDescription`. `1101` = aprobada. Aprobada: ```json {"type":"100","transactionId":954183,"ReasonCode":"1101","ReasonCodeDescription":"Transaccion aprobada","OrderHash":""} ``` Rechazada: ```json {"type":"100","transactionId":954183,"ReasonCode":"3","ReasonCodeDescription":"Invalid Retrieval reference number","OrderHash":""} ``` Error (`type` 300 o 400): ```json {"type":"400","message":"Order number: TYP974_172 does not exist"} ``` `"100"` indica que la modificación se procesó. Identificador de la transacción. Código de resultado de la modificación. Texto del resultado. Hash de la orden. Ver la nota sobre `orderHash` en [webhooks](/developers/api/webhooks#verificacion). Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · consult > Consulta del estado y el monto procesado de una transacción puntual. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/procesos-operativos/consult ```http POST /api/v1/consult ``` ## Qué hace [#que-hace] Consulta una transacción específica: devuelve el monto procesado y el estado de la transacción. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Número de orden consultado. Id de comercio. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "orderNumber": "1212122", "merchantId": "" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "message": "", "response": [ { "id_tilopay": 734312, "orderNumber": "1212122", "amount": "5.00", "currency": "USD", "merchantId": "88803956", "code": "1", "response": "Transacción aprobada", "auth": "123456", "commission": 0.18, "iva_commission": 0.02, "retention_iva": 0.27, "retention_rent": 0.09, "cost": 0.35, "cost_iva": 0.05, "net_to_liquidate": "4.04", "capture": "Capture", "card": "4021", "last": "5221", "environment": "Test", "type": "Payment", "date": "2024-07-31 16:59:20" } ] } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · consultTransactions > Consulta masiva de transacciones por rango de fechas, moneda, orden o correo. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-08-29 - url: https://tilopay.com/developers/api/procesos-operativos/consult-transactions ```http POST /api/v1/consultTransactions ``` ## Qué hace [#que-hace] Consulta transacciones por rango de fechas, con filtros opcionales. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Key de la integración Tilopay. Fecha de inicio, formato `Y-m-d H:i:s` — por ejemplo "2022-01-15 00:00:00". Fecha de fin, formato `Y-m-d H:i:s` — por ejemplo "2022-08-01 23:59:59". Indica si se obtienen solo transacciones aprobadas. | Código | Valor | | --- | --- | | 0 | Cualquiera | | 1 | Solo aprobadas | Ambiente de las transacciones a obtener. | Código | Valor | | --- | --- | | 0 | Producción | | 1 | Pruebas | Array de monedas que se desean obtener, por ejemplo ["USD", "CRC"]. Id de comercio. Número de orden. Correo del cliente. Número de autorización. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "key": "", "startDate": "2023-06-01 00:00:00", "endDate": "2023-06-30 23:59:59", "onlyAproved": 1, "environment": 1, "currency": [ "USD", "CRC" ], "merchantId": "", "orderNumber": "12135", "email": "customer@example.com", "auth": "123456" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "message": "", "response": [ { "id": 734329, "orderNumber": "12135", "amount": "5.00", "taxes": "0.00", "discount": "0.00", "discount_name": "", "currency": "USD", "merchantId": "", "code": "1", "response": "Transacción aprobada", "auth": "123456", "card": "4021", "last": "5221", "email": "customer@example.com", "commission": 0.18, "iva_commission": 0.02, "retention_iva": 0.27, "retention_rent": 0.09, "cost": 0.35, "cost_iva": 0.05, "net_to_liquidate": 4.04, "capture": "Capture", "type": "Payment", "environment": "Production", "date": "2024-07-31 16:59:20" }, { "id": 734330, "orderNumber": "12136", "amount": "5.00", "taxes": "0.00", "discount": "0.00", "discount_name": "", "currency": "USD", "merchantId": "", "code": "1", "response": "Transacción aprobada", "auth": "123456", "card": "4021", "last": "5221", "email": "customer@example.com", "commission": 0.18, "iva_commission": 0.02, "retention_iva": 0.27, "retention_rent": 0.09, "cost": 0.35, "cost_iva": 0.05, "net_to_liquidate": 4.04, "capture": "Capture", "type": "Payment", "environment": "Production", "date": "2024-07-31 17:25:35" } ] } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # API · Dividir liquidación (split) > División de la liquidación de una orden entre varios comercios facilitados. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/procesos-operativos/split ```http POST /api/v1/orders/liquidation/split ``` ## Qué hace [#que-hace] Divide la liquidación de una orden entre varios comercios. Solo aplica a comercios que usan Tilopay como facilitador de pago, y las órdenes resultantes se identifican con el prefijo `SL|`. Reglas: - Los comercios deben estar aprobados y ser del mismo país. - Si la partición es menor al monto total de la orden, el restante se le asigna al comercio que realizó la transacción original. - Solo aplica sobre órdenes aprobadas completamente. ## Autenticación [#autenticacion] Requiere el token bearer del API en el header `Authorization` — ver [autenticación](/developers/api/autenticacion). ## Parámetros [#parametros] Id de la orden aprobada en Tilopay. Array asociativo con las llaves `email` y `amount` de cada comercio con el que se divide la liquidación. Incluir al comercio propietario es opcional: si no se especifica su monto, se le asigna el excedente de la partición, y si se incluye y hay excedente, se le suma. Idioma de la solicitud. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "order_id": "1", "commerces": [ { "email": "commerce-1@example.com", "amount": "7.5" }, { "email": "commerce-2@example.com", "amount": "5.5" } ], "lang": "en" } ``` ## Respuesta [#respuesta] ```json { "type": "200", "message": "Great", "description": "Order splitted successfully", "response": { "total_order_splitted": 3, "order_id": 1, "order_number": "PFC000069-TYP785237_313", "order_key": "", "order_currency": "USD", "order_amount": "33.00", "splitted_orders": [ { "id": 1, "amount": 20, "commerce_name": "Commerce owner name", "commerce_email": "owner@example.com" }, { "id": 2, "amount": 7.5, "commerce_name": "Commerce name", "commerce_email": "commerce-1@example.com" }, { "id": 3, "amount": 5.5, "commerce_name": "Commerce name", "commerce_email": "commerce-2@example.com" } ] } } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # Cobros con tarjetas guardadas > Cobros con tarjetas guardadas: afiliación, grupos y lotes de cobro inmediatos o programados; 10 operaciones POST. - kind: api-index - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/cobros-tarjetas-guardadas ## Flujo [#flujo] 1. Creá un grupo (opcional). 2. Creá la URL de afiliación individual o de grupo y compartila. 3. El cliente registra su tarjeta en esa URL y queda como afiliado, con montos máximos diarios y mensuales. 4. Creá cobros a afiliados y/o grupos, inmediatos o programados por fecha. 5. Consultá los lotes y su detalle. El API de adquirencia no es idempotente: repetir `set/payments` genera otro cobro. [Reintentos seguros](/developers/reintentos-seguros). ## Autenticación [#autenticacion] Todas las operaciones son POST en `https://app.tilopay.com` y requieren el token bearer del API y la llave de la integración (`key`) en el cuerpo. ## Operaciones [#operaciones] - [Listar grupos](/developers/api/cobros-tarjetas-guardadas/get-groups) — `POST /api/v1/collect/get/groups` - [Listar afiliados](/developers/api/cobros-tarjetas-guardadas/get-affiliates) — `POST /api/v1/collect/get/affiliates` - [Listar lotes de cobro](/developers/api/cobros-tarjetas-guardadas/get-massive) — `POST /api/v1/collect/get/massive` - [Consultar detalle de lote](/developers/api/cobros-tarjetas-guardadas/get-massive-detail) — `POST /api/v1/collect/get/massive/detail` - [Crear grupo](/developers/api/cobros-tarjetas-guardadas/set-group) — `POST /api/v1/collect/set/group` - [Crear URL de afiliación individual](/developers/api/cobros-tarjetas-guardadas/set-url-affiliate) — `POST /api/v1/collect/set/urlaffiliate` - [Crear URL de afiliación a grupo](/developers/api/cobros-tarjetas-guardadas/set-url-group) — `POST /api/v1/collect/set/urlgroup` - [Editar afiliado](/developers/api/cobros-tarjetas-guardadas/edit-affiliate) — `POST /api/v1/collect/edit/affiliate` - [Editar grupo](/developers/api/cobros-tarjetas-guardadas/edit-group) — `POST /api/v1/collect/edit/group` - [Crear cobros](/developers/api/cobros-tarjetas-guardadas/set-payments) — `POST /api/v1/collect/set/payments` --- # API · Listar grupos > Listar grupos: POST /api/v1/collect/get/groups. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/cobros-tarjetas-guardadas/get-groups ```http POST /api/v1/collect/get/groups ``` ## Qué hace [#que-hace] Listar grupos. ## Autenticación [#autenticacion] Servidor: `https://app.tilopay.com`. Requiere el token bearer del API en `Authorization: Bearer ` y la llave de la integración en el cuerpo (`key`). [Obtener el token del API](/developers/api/autenticacion/token-api). ## Parámetros [#parametros] Llave de la integración. ## Ejemplo de request [#ejemplo-request] `` es el marcador de tu llave de integración. ```json { "key": "" } ``` ## Respuesta [#respuesta] groups: amount es el monto por defecto del grupo, como texto. `status`. `errors`. `groups`. ```json { "status": 200, "errors": "", "groups": [ { "id": 1, "name": "Grupo 1", "currency": "USD", "amount": "1000.00", "created_at": "2024-05-03T23:09:03.000000Z" }, { "id": 5, "name": "Colones", "currency": "CRC", "amount": "10.00", "created_at": "2024-05-08T23:52:41.000000Z" } ] } ``` ```schema { "type": "object", "properties": { "status": { "type": "integer" }, "errors": { "type": "string" }, "groups": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "integer" }, "name": { "type": "string" }, "currency": { "type": "string" }, "amount": { "type": "string" }, "created_at": { "type": "string" } } } } } } ``` --- # API · Listar afiliados > Listar afiliados: POST /api/v1/collect/get/affiliates. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/cobros-tarjetas-guardadas/get-affiliates ```http POST /api/v1/collect/get/affiliates ``` ## Qué hace [#que-hace] Listar afiliados. ## Autenticación [#autenticacion] Servidor: `https://app.tilopay.com`. Requiere el token bearer del API en `Authorization: Bearer ` y la llave de la integración en el cuerpo (`key`). [Obtener el token del API](/developers/api/autenticacion/token-api). ## Parámetros [#parametros] Llave de la integración. ID del grupo; 0 = todos. ## Ejemplo de request [#ejemplo-request] `` es el marcador de tu llave de integración. ```json { "key": "", "group": 0 } ``` ## Respuesta [#respuesta] affiliates contiene los datos del afiliado y sus límites diarios y mensuales. `status`. `errors`. `affiliates`. ```json { "status": 200, "errors": "", "affiliates": [ { "id": 2, "name": "Juan", "lastname": "Lopez", "email": "cliente@ejemplo.com", "company": "JuanSA", "phone": "88778878", "address": "San José, 100 m este", "city": "San Jose", "state": "CR-SJO", "zipcode": "10101", "country": "CR", "currency": "USD", "amount_max_daily": "1000.00", "amount_max_month": "1250.00", "base_amount": "10.00", "status": 1, "created_at": "2024-01-16T22:45:00.000000Z" }, { "id": 14, "name": "Ramon", "lastname": "Perez", "email": "otro@ejemplo.com", "company": null, "phone": null, "address": "San José", "city": "Alajuela", "state": "CR-A", "zipcode": "10101", "country": "CR", "currency": "USD", "amount_max_daily": "100.00", "amount_max_month": "1000.00", "base_amount": "0.00", "status": 1, "created_at": "2024-02-27T18:19:31.000000Z" } ] } ``` ```schema { "type": "object", "properties": { "status": { "type": "integer" }, "errors": { "type": "string" }, "affiliates": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "integer" }, "name": { "type": "string" }, "lastname": { "type": "string" }, "email": { "type": "string" }, "company": { "type": [ "string", "null" ] }, "phone": { "type": [ "string", "null" ] }, "address": { "type": "string" }, "city": { "type": "string" }, "state": { "type": "string" }, "zipcode": { "type": "string" }, "country": { "type": "string" }, "currency": { "type": "string" }, "amount_max_daily": { "type": "string" }, "amount_max_month": { "type": "string" }, "base_amount": { "type": "string" }, "status": { "type": "integer" }, "created_at": { "type": "string" } } } } } } ``` --- # API · Listar lotes de cobro > Listar lotes de cobro: POST /api/v1/collect/get/massive. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/cobros-tarjetas-guardadas/get-massive ```http POST /api/v1/collect/get/massive ``` ## Qué hace [#que-hace] Listar lotes de cobro. ## Autenticación [#autenticacion] Servidor: `https://app.tilopay.com`. Requiere el token bearer del API en `Authorization: Bearer ` y la llave de la integración en el cuerpo (`key`). [Obtener el token del API](/developers/api/autenticacion/token-api). ## Parámetros [#parametros] Llave de la integración. ## Ejemplo de request [#ejemplo-request] `` es el marcador de tu llave de integración. ```json { "key": "" } ``` ## Respuesta [#respuesta] Usá code para consultar el detalle de un lote. `status`. `errors`. `massives`. ```json { "status": 200, "errors": "", "massives": [ { "id": 1, "code": "R3VhKzhMNU1uaGg1ZjZRVGw4UGh0dz09", "created_at": "2024-05-15T04:36:58.000000Z" }, { "id": 3, "code": "UnBSdXN0bnZSc0owVXdvU1haVisxZz09", "created_at": "2024-05-15T04:56:59.000000Z" } ] } ``` ```schema { "type": "object", "properties": { "status": { "type": "integer" }, "errors": { "type": "string" }, "massives": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "integer" }, "code": { "type": "string" }, "created_at": { "type": "string" } } } } } } ``` --- # API · Consultar detalle de lote > Consultar detalle de lote: POST /api/v1/collect/get/massive/detail. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/cobros-tarjetas-guardadas/get-massive-detail ```http POST /api/v1/collect/get/massive/detail ``` ## Qué hace [#que-hace] Consultar detalle de lote. ## Autenticación [#autenticacion] Servidor: `https://app.tilopay.com`. Requiere el token bearer del API en `Authorization: Bearer ` y la llave de la integración en el cuerpo (`key`). [Obtener el token del API](/developers/api/autenticacion/token-api). ## Parámetros [#parametros] Llave de la integración. El code del listado de lotes. ## Ejemplo de request [#ejemplo-request] `` es el marcador de tu llave de integración. ```json { "key": "", "code": "UnBSdXN0bnZSc0owVXdvU1haVisxZz09" } ``` ## Respuesta [#respuesta] `responseText` trae el motivo del rechazo: `Daily amount exceeded` significa que el afiliado superó su monto máximo diario. El estado `Programmed` indica un cobro programado aún no procesado. `status`. `errors`. `payments`. ```json { "status": 200, "errors": "", "payments": [ { "id": 12, "collect_id": 2, "currency": "CRC", "amount": "100.00", "reference": "0", "auth": "", "date_programmed": "", "reason": "Cobro mensualidad", "responseText": "Daily amount exceeded", "status": "processed", "approved_payment": "0" }, { "id": 20, "collect_id": 2, "currency": "CRC", "amount": "100.00", "reference": "0", "auth": "123456", "date_programmed": "", "reason": "Cobro mensualidad", "responseText": "Approved", "status": "processed", "approved_payment": "0" }, { "id": 9, "collect_id": 2, "currency": "CRC", "amount": "100.00", "reference": "", "auth": "", "date_programmed": "2024-05-19", "reason": "Cobro mensualidad", "responseText": "", "status": "Programmed", "approved_payment": "0" } ] } ``` ```schema { "type": "object", "properties": { "status": { "type": "integer" }, "errors": { "type": "string" }, "payments": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "integer" }, "collect_id": { "type": "integer" }, "currency": { "type": "string" }, "amount": { "type": "string" }, "reference": { "type": "string" }, "auth": { "type": "string" }, "date_programmed": { "type": "string" }, "reason": { "type": "string" }, "responseText": { "type": "string", "description": "Rejection reason; Daily amount exceeded means the affiliate daily maximum was exceeded." }, "status": { "type": "string", "enum": [ "processed", "Programmed" ] }, "approved_payment": { "type": "string" } } } } } } ``` --- # API · Crear grupo > Crear grupo: POST /api/v1/collect/set/group. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/cobros-tarjetas-guardadas/set-group ```http POST /api/v1/collect/set/group ``` ## Qué hace [#que-hace] Crear grupo. ## Autenticación [#autenticacion] Servidor: `https://app.tilopay.com`. Requiere el token bearer del API en `Authorization: Bearer ` y la llave de la integración en el cuerpo (`key`). [Obtener el token del API](/developers/api/autenticacion/token-api). ## Parámetros [#parametros] Llave de la integración. Nombre del grupo. Moneda ISO 4217. Monto por defecto, texto con 2 decimales. ## Ejemplo de request [#ejemplo-request] `` es el marcador de tu llave de integración. ```json { "key": "", "currency": "USD", "amount": "100.00", "name": "Grupo Name" } ``` ## Respuesta [#respuesta] type es "200". id identifica el grupo creado. `type`. `errors`. `id`. ```json { "type": "200", "errors": "", "id": 10 } ``` ```schema { "type": "object", "properties": { "type": { "type": "string", "const": "200" }, "errors": { "type": "string" }, "id": { "type": "integer" } } } ``` --- # API · Crear URL de afiliación individual > Crear URL de afiliación individual: POST /api/v1/collect/set/urlaffiliate. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/cobros-tarjetas-guardadas/set-url-affiliate ```http POST /api/v1/collect/set/urlaffiliate ``` ## Qué hace [#que-hace] Crear URL de afiliación individual. ## Autenticación [#autenticacion] Servidor: `https://app.tilopay.com`. Requiere el token bearer del API en `Authorization: Bearer ` y la llave de la integración en el cuerpo (`key`). [Obtener el token del API](/developers/api/autenticacion/token-api). ## Parámetros [#parametros] Llave de la integración. Nombre del enlace. Moneda ISO 4217. Monto base. Monto máximo diario. Monto máximo mensual. ## Ejemplo de request [#ejemplo-request] `` es el marcador de tu llave de integración. ```json { "key": "", "name": "Name link", "currency": "USD", "base_amount": "5.00", "amount_max_daily": "10.00", "amount_max_month": "100.00" } ``` ## Respuesta [#respuesta] link es la URL donde el cliente registra su tarjeta. `type`. `errors`. `link`. ```json { "type": "200", "errors": "", "link": "https://app.tilopay.com/link/TWc9PXw0" } ``` ```schema { "type": "object", "properties": { "type": { "type": "string" }, "errors": { "type": "string" }, "link": { "type": "string" } } } ``` --- # API · Crear URL de afiliación a grupo > Crear URL de afiliación a grupo: POST /api/v1/collect/set/urlgroup. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/cobros-tarjetas-guardadas/set-url-group ```http POST /api/v1/collect/set/urlgroup ``` ## Qué hace [#que-hace] Crear URL de afiliación a grupo. ## Autenticación [#autenticacion] Servidor: `https://app.tilopay.com`. Requiere el token bearer del API en `Authorization: Bearer ` y la llave de la integración en el cuerpo (`key`). [Obtener el token del API](/developers/api/autenticacion/token-api). ## Parámetros [#parametros] Llave de la integración. Nombre del enlace. Moneda ISO 4217. Monto base. Monto máximo diario. Monto máximo mensual. ID del grupo. ## Ejemplo de request [#ejemplo-request] `` es el marcador de tu llave de integración. ```json { "key": "", "name": "Name link", "group": "1", "currency": "USD", "base_amount": "5.00", "amount_max_daily": "10.00", "amount_max_month": "100.00" } ``` ## Respuesta [#respuesta] Compartí link con los clientes que se afiliarán al grupo. `type`. `errors`. `link`. ```json { "type": "200", "errors": "", "link": "https://app.tilopay.com/link/TXc9PXw0" } ``` ```schema { "type": "object", "properties": { "type": { "type": "string" }, "errors": { "type": "string" }, "link": { "type": "string" } } } ``` --- # API · Editar afiliado > Editar afiliado: POST /api/v1/collect/edit/affiliate. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/cobros-tarjetas-guardadas/edit-affiliate ```http POST /api/v1/collect/edit/affiliate ``` ## Qué hace [#que-hace] Editar afiliado. ## Autenticación [#autenticacion] Servidor: `https://app.tilopay.com`. Requiere el token bearer del API en `Authorization: Bearer ` y la llave de la integración en el cuerpo (`key`). [Obtener el token del API](/developers/api/autenticacion/token-api). ## Parámetros [#parametros] Llave de la integración. ID del afiliado. name lastname company phone address city state zipcode country base_amount ## Ejemplo de request [#ejemplo-request] `` es el marcador de tu llave de integración. ```json { "key": "", "affiliateid": 2, "name": "Juan", "lastname": "Lopez", "company": "Tilo", "phone": "88998877", "address": "Escazu", "city": "San Jose", "state": "SJO", "zipcode": "10101", "country": "CR", "base_amount": "10.00" } ``` ## Respuesta [#respuesta] update devuelve success. `type`. `errors`. `update`. ```json { "type": "200", "errors": "", "update": "success" } ``` ```schema { "type": "object", "properties": { "type": { "type": "string" }, "errors": { "type": "string" }, "update": { "type": "string", "const": "success" } } } ``` --- # API · Editar grupo > Editar grupo: POST /api/v1/collect/edit/group. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/cobros-tarjetas-guardadas/edit-group ```http POST /api/v1/collect/edit/group ``` ## Qué hace [#que-hace] Editar grupo. ## Autenticación [#autenticacion] Servidor: `https://app.tilopay.com`. Requiere el token bearer del API en `Authorization: Bearer ` y la llave de la integración en el cuerpo (`key`). [Obtener el token del API](/developers/api/autenticacion/token-api). ## Parámetros [#parametros] Llave de la integración. ID del grupo. Monto por defecto del grupo. Nombre del grupo. ## Ejemplo de request [#ejemplo-request] `` es el marcador de tu llave de integración. ```json { "key": "", "groupid": 1, "amount": "800.00", "name": "Grupo Name" } ``` ## Respuesta [#respuesta] update devuelve success. `type`. `errors`. `update`. ```json { "type": "200", "errors": "", "update": "success" } ``` ```schema { "type": "object", "properties": { "type": { "type": "string" }, "errors": { "type": "string" }, "update": { "type": "string", "const": "success" } } } ``` --- # API · Crear cobros > Crear cobros: POST /api/v1/collect/set/payments. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/api/cobros-tarjetas-guardadas/set-payments ```http POST /api/v1/collect/set/payments ``` ## Qué hace [#que-hace] Crear cobros. ## Autenticación [#autenticacion] Servidor: `https://app.tilopay.com`. Requiere el token bearer del API en `Authorization: Bearer ` y la llave de la integración en el cuerpo (`key`). [Obtener el token del API](/developers/api/autenticacion/token-api). ## Parámetros [#parametros] Llave de la integración. También aplica a cobros programados por fecha. 1 captura; 0 solo autoriza. Concepto del cobro. Afiliados: arreglo de `{id, amount, currency, date}`. Grupos: arreglo de `{id, amount, currency, date}`; amount es el monto por afiliado. El campo `date` vacío indica cobro inmediato; `YYYY-MM-DD` programa el cobro. En `groups`, `amount` es el monto por afiliado. ## Ejemplo de request [#ejemplo-request] `` es el marcador de tu llave de integración. ```json { "key": "", "capture": 1, "reason": "Cobro mensualidad", "users": [ { "id": "5", "amount": "500.00", "currency": "CRC", "date": "" }, { "id": "32", "amount": "1000.00", "currency": "CRC", "date": "2024-06-20" }, { "id": "25", "amount": "10.00", "currency": "USD", "date": "2024-06-20" } ], "groups": [ { "id": "10", "amount": "25.00", "currency": "USD", "date": "" } ] } ``` ## Respuesta [#respuesta] batch es el code del lote para get/massive/detail. date vacío = cobro inmediato; YYYY-MM-DD = programado. Repetir esta operación genera otro cobro. `status`. `errors`. `users_errors`. `groups_errors`. `programeds`. `batch`. ```json { "status": 200, "errors": "", "users_errors": "", "groups_errors": "", "programeds": { "users": [ "5", "32", "25" ], "groups": [ "10" ] }, "batch": "SGZqbHlHalJiWmRNSEszd3ZEZHo4dz09" } ``` ```schema { "type": "object", "properties": { "status": { "type": "integer" }, "errors": { "type": "string" }, "users_errors": { "type": [ "string", "array" ], "items": {} }, "groups_errors": { "type": [ "string", "array" ], "items": {} }, "programeds": { "type": "object", "properties": { "users": { "type": "array", "items": { "type": "string" } }, "groups": { "type": "array", "items": { "type": "string" } } } }, "batch": { "type": "string" } } } ``` ## Respuesta de error [#respuestas-de-error] HTTP 400: ```json { "status": "400", "errors": "Please verify the data sent", "users_errors": [ { "id": "32", "amount": "1000.00", "currency": "CRC", "date": "invalidDate" } ], "groups_errors": [ { "id": "10", "amount": "25.00", "currency": null, "date": null } ] } ``` [Reintentos seguros](/developers/reintentos-seguros). --- # Webhooks > Qué eventos existen, cuántos reintentos hay, en qué formato llegan y cómo confirmar el estado de un cobro. - kind: concept - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/webhooks ## Recurrencia [#recurrencia] Son 6 campos que se configuran al **crear o editar un plan**. Todos opcionales. | Campo | Qué es | |---|---| | `webhook_subscribe` | Webhook de suscripción | | `webhook_payment` | Webhook de cobro | | `webhook_rejected` | Webhook de cobro rechazado | | `webhook_unsubscribe` | Webhook de baja | | `webhook_reactive` | Webhook de reactivación | | `thanks_url` | **No es un webhook:** es un callback GET | ## Links de pago [#links-de-pago] Se configura `webhook_url` al crear el link. ## Reintentos [#reintentos] | Origen | Intentos | Cuándo reintenta | |---|---|---| | Recurrencia | 5 | Cuando tu respuesta es 400, 404, 502, 504 o 403 | | Compras | 1 | — | Se da por entregado con un **HTTP 200**. Respondé 200 en cuanto recibás el evento y procesalo aparte: cualquier otra cosa cuenta como fallo, y en compras no hay segundo intento. ## Formato [#formato] JSON. ## El token de tarjeta [#token] | Origen | Token | |---|---| | Recurrencia | **No se envía** | | Compras | Se envía y **es utilizable** | ## Verificación de origen [#verificacion] > **Advertencia:** La única verificación de origen disponible es el `orderHash`, y su algoritmo no es público: > se solicita escribiendo a `soporte@tilopay.com`. > > Mientras no tengás el algoritmo, no tomés decisiones de negocio irreversibles solo con el > contenido del webhook: confirmá el estado contra el API antes de despachar o liberar un > servicio. ## Webhook del flujo principal [#processpayment] > **Nota:** `processPayment` también tiene webhook. Su especificación técnica (los campos que envía) te la entregamos cuando la solicitás, para que tu equipo lo implemente: > escribí a `soporte@tilopay.com` para recibirlo. --- # SDK JavaScript > Camino de integración en el que el formulario de tarjeta vive en tu página y el SDK manda los datos directo a Tilopay. - kind: guide - status: stable - sdk_version: 2.1.1 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/sdk ## Qué es [#que-es] Los campos de tarjeta viven en tu página. El SDK V2 toma control de esos inputs y manda los datos **del navegador directo a Tilopay**: no pasan por tu servidor. ## Para quién es [#para-quien] Para equipos que quieren controlar el diseño del checkout sin que los datos de tarjeta toquen su backend. Necesitás frontend con JavaScript y un backend mínimo para obtener el token del SDK. ## Cómo se arma, en orden [#orden] 1. **Credenciales.** No hay credenciales de sandbox compartidas: obtené las tuyas en [registro de developer](/developers/registro). 2. **Token del SDK.** Tu backend lo pide con `POST /api/v1/loginSdk`. Ver [autenticación](/developers/api/autenticacion). 3. **Cargá el script.** Ver [instalación](/developers/sdk/instalacion). 4. **Poné los inputs con los ids del contrato** y el contenedor `responseTilopay`. Ver [campos del formulario](/developers/sdk/campos-del-formulario). 5. **Iniciá la compra** con [`Tilopay.Init()`](/developers/sdk/reference/init) y mostrale al cliente los métodos de pago que devuelve. 6. **Cerrá la compra** con [`Tilopay.startPayment()`](/developers/sdk/reference/startpayment). El SDK maneja 3DS y renderiza el resultado en tu URL de `redirect`. 7. **Confirmá el resultado en tu servidor.** El redirect es del cliente; antes de entregar el producto, confirmá el estado con el API. Ver [confirmar el resultado](#confirmar). ## Flujo de métodos [#flujo] ## SINPE Móvil: confirmación y plazo [#sinpe-confirmacion] Cuando llega la transferencia, el SDK redirige a tu `redirect`; si enviaste `webhook`, Tilopay también lo notifica. El SDK no fija un plazo, pero Tilopay asocia transferencias con órdenes SINPE Móvil creadas en los últimos **25 minutos**: el cliente debe transferir dentro de ese plazo. La sesión depende de la vigencia del token del SDK. ```text Requerido: Init() ──────────────────────────────► startPayment() Opcionales: getCardType() (mostrar el ícono de la marca) updateOptions() (si cambian datos) ``` También podés aceptar [Apple Pay](/developers/sdk/apple-pay): el SDK dibuja el botón dentro del formulario. ## Confirmá el resultado en tu servidor [#confirmar] Al finalizar, el navegador del cliente llega a tu URL de `redirect` con los parámetros del resultado: `code`, `description`, `auth`, `order`, `tpt`, `tilopay-transaction`, `OrderHash` y `returnData`. Ver la tabla completa en [parámetros que llegan al redirect](/developers/api/hosted-payment-page/process-payment#parametros-del-redirect). - `code = 1` significa transacción aprobada; cualquier otro valor es un rechazo. - El redirect lo recibe el navegador del cliente, así que no es prueba suficiente: **antes de entregar el producto, confirmá el estado con `POST /api/v1/consult` desde tu servidor**. - `OrderHash` es un string único por transacción: su algoritmo no es público y se solicita escribiendo a `soporte@tilopay.com`. ## Antes de asumir que estás en pruebas [#entornos] Pruebas y producción comparten host: el modo se verifica con el campo `environment` de `Init()` (`"TEST"` o `"PROD"`). Ver [entornos](/developers/entornos). ## Ejemplo completo [#ejemplo-completo] Formulario dentro de `.payFormTilopay`, los cinco campos, botones Pagar y Actualizar, `responseTilopay` fuera del formulario, el script v2, `Init()` con todos los campos, la carga de `methods` y `cards` en sus select y `startPayment()`. ```html
``` ## Cumplimiento [#cumplimiento] Los datos de tarjeta no pasan por tu servidor, pero tu página los captura: consultá con tu equipo de cumplimiento el alcance que te corresponde. --- # Obtener token del SDK > Login del SDK: devuelve el token que usa Tilopay.Init() en el navegador. - kind: api-operation - status: stable - api_version: v1 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api/autenticacion/token-sdk ```http POST /api/v1/loginSdk ``` ## Qué hace [#que-hace] Devuelve el token de seguridad necesario para consumir el SDK. Las tres credenciales se obtienen en [Panel administrativo · Integración con plataformas](https://admin.tilopay.com/platform-integrations). ## Autenticación [#autenticacion] No requiere token: es la operación que lo emite. Ver [autenticación](/developers/api/autenticacion). > **Advertencia:** Este login corre en tu servidor, nunca en el navegador. `apiuser`, `password` y `key` > son secretos del comercio: no se exponen en el frontend. Al navegador solo baja el token > que devuelve esta operación. ## Parámetros [#parametros] Usuario de API del comercio. Contraseña de API del comercio. Api key del comercio. ## Ejemplo de request [#request] Los valores `<...>` son marcadores: reemplazalos por tus credenciales y datos. ```json { "apiuser": "", "password": "", "key": "" } ``` ## Respuesta [#respuesta] ```json { "access_token": "351d477adaaa51cdbb33ae4b4b8c843aa759f131c1c38415180b5035543d59d2f23f4e049706f5fa71c5f0d9ff763960a3cd035b4c1cefa428c90bedb672f780", "token_type": "bearer", "expires_in": "2023-06-05 13:32:06" } ``` ## Respuestas de error [#respuestas-de-error] Credenciales inválidas → HTTP 401: ```json { "error": "Unauthorized" } ``` Para interpretar una respuesta que no es de éxito, ver [cómo leer una respuesta de error](/developers/api/procesos-operativos/errors). --- # Instalación del SDK > La etiqueta script del SDK V2, el historial de versiones, los dominios para tu Content-Security-Policy y qué garantías de versionado no hay. - kind: guide - status: stable - sdk_version: 2.1.1 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/sdk/instalacion ## El script [#script] ```html ``` Cargalo antes de tu propio código de checkout. El SDK expone el objeto global `Tilopay`. La versión vigente es la **2.1.1**. ## jQuery no es requerido [#jquery] > **Nota:** jQuery NO es requerido. Desde la versión 2.0.0 el SDK está escrito en JavaScript: podés > instalarlo sin jQuery en la página. ## Historial de versiones [#versiones] | Versión | Fecha | Cambio | |---|---|---| | 1.0.0 | 29/07/2022 | Formulario de pago Tilopay | | 1.1.0 | 05/10/2022 | Tarjetas guardadas y SINPE Móvil | | 2.0.0 | 01/06/2023 | Migración de jQuery a JavaScript | | 2.1.0 | 30/08/2023 | [`InitTokenize()`](/developers/sdk/reference/init-tokenize) para guardar tarjetas | | 2.1.1 | — | [Apple Pay](/developers/sdk/apple-pay) | ## Dominios para Content-Security-Policy [#csp] Si tu sitio usa Content-Security-Policy, permití los orígenes que carga el SDK: | Origen | Cuándo | |---|---| | `https://app.tilopay.com` | Siempre | | `https://api.tokenex.com` | Siempre | | `https://h.online-metrix.net` | Siempre | | `https://storage.googleapis.com` | Siempre | | `https://cdn.jsdelivr.net` | Siempre | | `https://applepay.cdn-apple.com` | Solo si usás [Apple Pay](/developers/sdk/apple-pay) | ## Lo que no hay [#garantias] > **Advertencia:** No hay versionado inmutable, no hay hash SRI y no hay changelog. La URL > `/sdk/v2/sdk_tpay.min.js` no está anclada a una versión concreta: su contenido puede > cambiar sin aviso previo y sin una nota de cambios pública. > > Consecuencias prácticas: > > - No podés fijar `integrity="sha384-..."` en la etiqueta `script`, porque el archivo cambia. > - No podés depender de un número de build para reproducir un bug. > - Conviene tener pruebas de humo de tu checkout que corran periódicamente, no solo al > desplegar. ## Aplicaciones de una sola página [#spa] Funciona en React y Vue. Llamá `Init()` después de que los campos estén montados en el DOM: los usa de inmediato y falla si no existen. Si el formulario se vuelve a montar, volvé a llamar `Init()`. React Native WebView no está probado por Tilopay y puede desactivar Apple Pay; probalo en tu entorno antes de salir a producción. ## Qué sigue [#que-sigue] - [Campos del formulario](/developers/sdk/campos-del-formulario) — los ids que el SDK busca. - [`Tilopay.Init()`](/developers/sdk/reference/init) — iniciar la compra. --- # Campos del formulario > Los ids tlpy_* que el SDK V2 busca dentro del div payFormTilopay y el contenedor responseTilopay que necesita para 3DS. - kind: concept - status: stable - sdk_version: 2.1.1 - last_verified: 2026-10-21 - url: https://tilopay.com/developers/sdk/campos-del-formulario El SDK V2 no renderiza el formulario: toma control de los inputs que ya existen en tu página, buscándolos por `id`. Esos ids son un contrato — si cambiás uno, el SDK deja de encontrar el campo. > **Advertencia:** El contenedor `payFormTilopay` es obligatorio. Todos los campos `tlpy_*` (y el div de > [Apple Pay](/developers/sdk/apple-pay)) deben estar dentro de un `div` con la clase > `payFormTilopay`: el SDK busca ese contenedor para escuchar los campos. El contenedor > `responseTilopay` va fuera de ese `div`. ## Campos [#campos] Contiene el id del método de pago obtenido de Tilopay. Puede estar visible u oculto, a tu discreción. Contiene el id de la tarjeta guardada obtenida de Tilopay. Debe existir en el DOM; puede estar oculto si el método de pago no lo usa. Número de tarjeta. Debe existir en el DOM; puede estar oculto si el método de pago no lo usa. Fecha de expiración en formato mes/año, por ejemplo `12/30`. Debe existir en el DOM; puede estar oculto si el método de pago no lo usa. Código de seguridad. Debe existir en el DOM; puede estar oculto si el método de pago no lo usa. Cuando el cliente usa una tarjeta guardada, hay que habilitar este campo para que digite el CVV. Para [Apple Pay](/developers/sdk/apple-pay): el SDK dibuja ahí el botón de Apple Pay. Va dentro de `payFormTilopay`. Opcional, para Apple Pay. Su valor cambia a `"cancelled"` y dispara `change` cuando el comprador cierra la hoja de Apple Pay. Contenedor requerido, **fuera de `payFormTilopay`**. Es donde el SDK monta el flujo 3DS. ## El teléfono de Yappy no viaja por el DOM [#yappy] El teléfono de Yappy **no** se toma de un campo del formulario: se envía en el parámetro `phoneYappy` de [`Init()`](/developers/sdk/reference/init) o de [`updateOptions()`](/developers/sdk/reference/update-options). ## Estructura de ejemplo [#estructura] El `div` con la clase `payFormTilopay`, los `id` de los inputs y `responseTilopay` son obligatorios; los demás `div` son libres. ```html
``` --- # Apple Pay > Cómo aceptar Apple Pay con el SDK V2 (2.1.1) — requisitos, pasos, ejemplo, datos de la hoja de pago y problemas frecuentes. - kind: guide - status: stable - sdk_version: 2.1.1 - last_verified: 2026-10-21 - url: https://tilopay.com/developers/sdk/apple-pay ## Qué es [#que-es] El SDK dibuja el botón de Apple Pay dentro de tu formulario, abre la hoja de pago de Apple y procesa el pago con el token cifrado de Apple. El comprador no digita la tarjeta. ## Requisitos [#requisitos] | Requisito | Detalle | |---|---| | Cuenta en producción | En modo de pruebas el botón no aparece y `applePaySupported` es `false`: no se puede probar en pruebas. | | Método de pago con Apple Pay | En `init.methods` el método trae `apple_pay = 1`. Si tu método no lo trae, el botón no se muestra. | | Dominio certificado | El dominio tiene que estar certificado para Apple Pay en tu cuenta de Tilopay. La comparación es exacta: `www.comercio.com` y `comercio.com` son dominios distintos. Para certificarlo escribí a soporte@tilopay.com con el dominio exacto. | | HTTPS | La página se sirve por HTTPS. | | Navegador | Safari en un dispositivo Apple con Apple Pay configurado. | | Tarjetas | Visa, Mastercard o American Express. | ## Pasos [#pasos] 1. Cargá el [SDK v2](/developers/sdk/instalacion). 2. Dentro de `.payFormTilopay` agregá `
` donde va el botón y, opcional, `` para saber cuándo el comprador cierra la hoja (su valor cambia a `"cancelled"` y dispara `change`). 3. Llamá [`Init()`](/developers/sdk/reference/init) como siempre (token, moneda, monto, orden, facturación, `capture` y `redirect`). `applePaySupported: true` indica que se cumplen los requisitos para ese dominio y navegador. 4. Llená `#tlpy_payment_method` con `init.methods`. 5. El botón aparece cuando el select dispara el evento `change` con un método que tiene Apple Pay. Si seleccionás el método por código, dispará `select.dispatchEvent(new Event('change'))`. 6. Al tocar el botón, el SDK abre Apple Pay y, cuando el comprador autoriza, procesa el pago: si se aprueba redirige a `redirect`; si el banco pide 3DS lo muestra en `#responseTilopay`. > **Nota:** Los campos de tarjeta siguen siendo obligatorios. `tlpy_cc_number`, > `tlpy_cc_expiration_date` y `tlpy_cvv` tienen que estar en el HTML aunque el comprador pague con > Apple Pay, porque el SDK los inicializa en `Init()`. ## Ejemplo [#ejemplo] ```html
``` ## Datos de la hoja de Apple Pay [#hoja] | Dato | Valor | |---|---| | País | `CR` | | Moneda | La de `Init()`, en mayúsculas | | Redes | `visa`, `mastercard` y `amex` | | Capacidad | `supports3DS` | | Etiqueta | `Tilopay: ` | | Monto | El de `Init()` | ## Comportamiento a tener en cuenta [#comportamiento] - El resultado del pago con Apple Pay **no se devuelve a tu código** (el botón llama al SDK directamente): te llega en la URL de `redirect` como cualquier pago. Confirmalo con `POST /api/v1/consult` desde tu servidor. Ver [confirmar el resultado](/developers/sdk#confirmar). - Solo podés escuchar la cancelación, con `tlpy_apple_pay_cancel`. - Si el pago falla, la hoja queda abierta hasta que el comprador la cierre o expire, y el detalle queda en la consola del navegador. ## Problemas frecuentes [#problemas] | Síntoma | Causa y solución | |---|---| | `applePaySupported` es `false` | Cuenta en pruebas, ningún método con `apple_pay = 1`, navegador sin Apple Pay o dominio no certificado. Cuando es el dominio, la consola muestra `Apple Pay not allowed for this domain`. | | `applePaySupported` es `true` pero no aparece el botón | No está el div dentro de `.payFormTilopay`, el método elegido no tiene Apple Pay o el select no disparó `change`. | | Funciona con un dominio y no con `www` | Certificá también la otra forma o usá siempre la certificada. | | El botón abre la hoja y se cierra enseguida | Falló la validación del comercio con Apple: revisá que la certificación del dominio esté vigente y escribí a soporte@tilopay.com con el dominio y la hora. | | El comprador autoriza y la hoja se queda cargando | El pago falló: revisá la consola y consultá la transacción por número de orden. | --- # Tilopay.Init() > Inicia una compra: autentica el checkout y devuelve el entorno, los métodos de pago disponibles y las tarjetas guardadas del cliente. - kind: sdk-method - status: stable - sdk_version: 2.1.1 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/sdk/reference/init Inicia una compra. Autentica el checkout con el token del SDK y devuelve los métodos de pago disponibles para vos. Para guardar una tarjeta sin cobrarla, usá [`Tilopay.InitTokenize()`](/developers/sdk/reference/init-tokenize). ## Firma [#firma] ```js await Tilopay.Init({ /* parámetros */ }) ``` ## Parámetros [#parametros] URL a la que Tilopay notifica el resultado de pagos con SINPE Móvil y Yappy. Token del SDK, obtenido por tu backend con `POST /api/v1/loginSdk`. Ver [token del SDK](/developers/api/autenticacion/token-sdk). Moneda de la compra, ISO 4217. Idioma del checkout: `es` o `en`. Monto de la compra. Correo del cliente. Es necesario para que la respuesta traiga las tarjetas guardadas. Número de orden. **No se puede repetir.** Ver [reintentos seguros](/developers/reintentos-seguros). Tipo de identificación del cliente. Obligatorio para SINPE Móvil. Ver la [tabla de tipos](/developers/sdk/reference/update-options#tipos-de-identificacion). Número de identificación del cliente. Obligatorio para SINPE Móvil. Nombre del cliente. Apellidos del cliente. Dirección 1 del cliente. Dirección 2 del cliente. Ciudad. Provincia o estado. Código postal. País, ISO 3166-1 alpha-2. Teléfono del cliente. Nombre de quien recibe el envío. Apellidos de quien recibe el envío. Dirección 1 de envío. Dirección 2 de envío. Ciudad de envío. Provincia o estado de envío. Código postal de envío. País de envío, ISO 3166-1 alpha-2. Teléfono de envío. `0` autoriza; `1` autoriza y captura. URL donde el SDK renderiza la respuesta final de la compra. `1` guarda la tarjeta del cliente en Tilopay; `0` no la guarda. Valores `"V1"` o `"V2"`. Si no se envía, el hash de la respuesta final se fabrica con **V2**. Se envía en esta primera llamada. Se devuelve tal cual en la respuesta final del pago y se recupera en la URL de respuesta de la transacción. Soporta hasta **65.535 caracteres**, aunque un valor muy extenso puede afectar la URL de respuesta. Podés enviar un array serializado en base64 para que cumpla el formato de string. Teléfono Yappy. Obligatorio cuando se paga con Yappy. No se toma del DOM. ## Llamada [#llamada] ```js const init = await Tilopay.Init({ token: "", currency: "CRC", language: "es", amount: 100.0, billToEmail: "cliente@ejemplo.com", orderNumber: "ORD-2026-000123", billToFirstName: "Ana", billToLastName: "Rojas", billToCountry: "CR", capture: 1, redirect: "https://ejemplo.com/respuesta", subscription: 0, }); ``` ## Respuesta [#respuesta] ```json { "message": "Success", "environment": "PROD", "sinpemovil": { "code": "TB095", "amount": "100.00" }, "methods": [ { "id": "", "name": "Tarjeta", "type": "card", "apple_pay": 0 }, { "id": "", "name": "SINPE Móvil", "type": "sinpemovil", "apple_pay": 0 } ], "cards": [ { "id": "411112555451111:Ref", "name": "4111********1111", "brand": "visa" } ], "applePaySupported": false } ``` `Success`, o la descripción del error. `"PROD"` producción, `"TEST"` pruebas. Ver [entornos](/developers/entornos). Objeto con `code` y `amount`, presente cuando tenés SINPE Móvil. Los datos completos, incluido el teléfono destino, se obtienen con [`getSinpeMovil()`](/developers/sdk/reference/get-sinpe-movil). Arreglo de `{id, name, type, apple_pay}` con los métodos de pago disponibles. `type` vale `card`, `sinpemovil` o `yappy`; cada método trae `apple_pay` (`0` o `1`). Arreglo de `{id, name, brand}` con las tarjetas guardadas del cliente. `true` cuando se cumplen los requisitos de [Apple Pay](/developers/sdk/apple-pay) para ese dominio y navegador. ### En caso de error [#respuesta-de-error] En caso de error: ```json { "message": "", "methods": [], "cards": [] } ``` ## Formato del id de método de pago [#formato-id-metodo] No interpretes el id: guardalo tal cual como valor del select y usá el campo `type` de cada método (`card`, `sinpemovil` o `yappy`) para decidir qué campos mostrar. ## Yappy [#yappy] El método trae `type: "yappy"`; su id tiene la forma `:18::…`. El formulario necesita los campos obligatorios de `Init()` más `phoneYappy`. Al llamar `startPayment()`, el SDK redirige a una página de Tilopay que abre Yappy; el cliente aprueba el pago en su app. Al terminar, Tilopay notifica al `webhook` (si se envió) y redirige a tu `redirect` con `code`, `auth`, `order` y `OrderHash`. Si cancela, la orden queda rechazada; sin respuesta en **7 minutos**, queda como “Transacción expirada”. ## Tarjetas guardadas [#tarjetas-guardadas] - Para que la respuesta traiga `cards` es **obligatorio enviar `billToEmail`**. - Una vez obtenidas las tarjetas, **el correo ya no se puede cambiar** con [`updateOptions()`](/developers/sdk/reference/update-options). - El cliente puede elegir una tarjeta guardada o digitar una nueva. - Al elegir una tarjeta guardada, **habilitá `tlpy_cvv`** para que el cliente digite el código. --- # Tilopay.InitTokenize() > Inicia el guardado de una tarjeta sin compra: valida la tarjeta con un cobro de USD 0.10 que se reversa de inmediato. - kind: sdk-method - status: stable - sdk_version: 2.1.1 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/sdk/reference/init-tokenize Inicia el guardado de una tarjeta **sin compra**. Se usa con los mismos [campos del formulario](/developers/sdk/campos-del-formulario) que `Init()` y se cierra con [`Tilopay.startPayment()`](/developers/sdk/reference/startpayment). > **Nota:** Cobro de validación. Para validar la tarjeta, Tilopay hace un cobro de USD 0.10 (o su > equivalente en la moneda) que se reversa de inmediato; el cliente lo ve devuelto en minutos. Guardá el token que recibís y asocialo al correo del cliente para usarlo después. ## Firma [#firma] No envíes `orderNumber`: el SDK usa su propio identificador de sesión. Tilopay fija el monto de validación. ```js await Tilopay.InitTokenize({ /* parámetros */ }) ``` ## Parámetros del redirect [#parametros-del-redirect] El redirect trae por query params `code`, `crd`, `order`, `brand`, `last-digits` y `OrderHash`. `crd` es el token de la tarjeta y solo trae valor cuando `code = 1`; guardalo asociado al correo del cliente. `order` lo genera Tilopay, no el comercio. ## Parámetros [#parametros] Token del SDK, obtenido con `POST /api/v1/loginSdk`. Moneda, ISO 4217. Idioma: `es` o `en`. Correo del cliente. Nombre del cliente. Apellidos del cliente. Dirección 1 del cliente. Dirección 2 del cliente. Ciudad. Provincia o estado. Código postal. País, ISO 3166-1 alpha-2. Teléfono del cliente. URL donde el SDK renderiza la respuesta final. ## Llamada [#llamada] ```js const init = await Tilopay.InitTokenize({ token: "", currency: "USD", language: "es", billToEmail: "cliente@ejemplo.com", billToFirstName: "Ana", billToLastName: "Rojas", redirect: "https://ejemplo.com/respuesta", }); ``` ## Respuesta [#respuesta] ```json { "message": "Success", "environment": "PROD", "methods": [ { "id": "", "name": "Tarjeta", "type": "card" } ] } ``` En caso de error: ```json { "message": "", "methods": [] } ``` --- # Tilopay.startPayment() > Cierra la compra. No recibe parámetros; redirige a la URL de redirect o muestra 3DS en responseTilopay. - kind: sdk-method - status: stable - sdk_version: 2.1.1 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/sdk/reference/startpayment Cierra la compra iniciada con [`Tilopay.Init()`](/developers/sdk/reference/init) (o el guardado iniciado con [`InitTokenize()`](/developers/sdk/reference/init-tokenize)). ## Firma [#firma] ```js await Tilopay.startPayment() ``` No recibe parámetros. **Requiere que los datos estén completos**: método de pago, datos de tarjeta y los datos que el método necesite, enviados en `Init()` o en [`updateOptions()`](/developers/sdk/reference/update-options). ## 3DS: lo maneja el SDK [#tres-ds] **El SDK maneja todo el flujo de 3D Secure.** Si el banco lo pide, el SDK lo muestra en el contenedor `responseTilopay`: ```html
``` Ver [campos del formulario](/developers/sdk/campos-del-formulario#campos). ## Dónde llega el resultado [#resultado] Cuando el pago sale bien, el SDK redirige y la promesa se resuelve con `{ "message": "" }`, sin datos del pago. En error devuelve `{ "message": "" }`. Si todo sale bien, el SDK redirige a la URL indicada en `redirect`. Ese redirect lo recibe el navegador del cliente, así que antes de entregar el producto [confirmá el resultado en tu servidor](/developers/sdk#confirmar). Si hay un error, el método devuelve la descripción: ```json { "message": "" } ``` Con SINPE Móvil, mientras la transferencia no llegue, `startPayment()` devuelve el error de SINPE en espera. Ver [`getSinpeMovil()`](/developers/sdk/reference/get-sinpe-movil). --- # Tilopay.getCardType() > Devuelve la marca de la tarjeta que el cliente digitó o eligió, en minúsculas, para mostrarle el ícono. - kind: sdk-method - status: stable - sdk_version: 2.1.1 - last_verified: 2026-10-21 - url: https://tilopay.com/developers/sdk/reference/get-card-type Devuelve la marca de la tarjeta a partir del número que el cliente ya digitó en `tlpy_cc_number` (o de la tarjeta guardada que eligió). El uso típico es mostrar el ícono de la marca. ## Firma [#firma] ```js await Tilopay.getCardType() ``` No recibe parámetros. **Precondición:** el cliente ya tiene que haber digitado el número de tarjeta o elegido una tarjeta guardada. ## Llamada [#llamada] ```js const type = await Tilopay.getCardType(); ``` ## Respuesta [#respuesta] ```json { "message": "visa" } ``` La marca de la tarjeta, en minúsculas. Si no reconoce la marca, viene vacío. ## Valores de marca [#marcas-soportadas] | Estado | Valores | |---|---| | Soportadas | `visa`, `mastercard`, `amex` | | No soportadas | `elo`, `visaelectron`, `maestro`, `forbrugsforeningen`, `dankort`, `hipercard`, `dinersclub`, `discover`, `unionpay`, `jcb`, `laser` | Usá el resultado solo para presentación: la validación de la marca la hace Tilopay al procesar el cobro, no este método. --- # Tilopay.getSinpeMovil() > Devuelve los datos que hay que mostrarle al cliente para pagar por SINPE Móvil: teléfono destino, monto exacto y código. - kind: sdk-method - status: stable - sdk_version: 2.1.1 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/sdk/reference/get-sinpe-movil SINPE Móvil no se cobra desde el formulario: el cliente hace la transferencia desde su propio banco. Este método arma los datos del método SINPE seleccionado que hay que mostrarle — teléfono destino, monto exacto y código de descripción. ## Cuándo se usa [#cuando] Cuando tenés un método SINPE Móvil disponible y el cliente lo selecciona de la lista que devolvió [`Init()`](/developers/sdk/reference/init). ## Firma [#firma] ```js await Tilopay.getSinpeMovil() ``` No recibe parámetros. **Precondiciones:** - El cliente tiene que haber seleccionado SINPE Móvil como método de pago. - `typeDni` y `dni` tienen que haberse enviado antes, por `Init()` o por [`updateOptions()`](/developers/sdk/reference/update-options). ## Llamada [#llamada] ```js const params = await Tilopay.getSinpeMovil(); ``` ## Respuesta [#respuesta] ```json { "message": "Success", "code": "863", "amount": 10, "number": "70599200" } ``` `Success` cuando la operación salió bien; la descripción del error si no. El código que el cliente debe escribir en la descripción de la transferencia. Es lo que permite identificar el pago. El monto exacto que debe transferir. El número de teléfono destino de la transferencia. ### En caso de error [#respuesta-de-error] Devuelve un objeto con la descripción del error y los demás campos vacíos: ```json { "message": "", "code": "", "amount": "", "number": "" } ``` ## SINPE Móvil: confirmación y plazo [#sinpe-confirmacion] Cuando llega la transferencia, el SDK redirige a tu `redirect`; si enviaste `webhook`, Tilopay también lo notifica. El SDK no fija un plazo, pero Tilopay asocia transferencias con órdenes SINPE Móvil creadas en los últimos **25 minutos**: el cliente debe transferir dentro de ese plazo. La sesión depende de la vigencia del token del SDK. ## Qué hacer con estos datos [#que-hacer] - Al elegir SINPE Móvil, ocultá los campos de tarjeta y mostrá un mensaje como: *«Para pagar con SINPE Móvil, transferí al teléfono 8888 8888 el monto exacto ₡100,00 e indicá en la descripción TB095»*. - Opcionalmente, agregá un botón «Ya hice el SINPE Móvil» que, al tocarlo, muestre que se está esperando el depósito. Antes de habilitarlo, asegurate de tener correo, `typeDni` y `dni`. - Mientras la transferencia no llegue, [`startPayment()`](/developers/sdk/reference/startpayment) devuelve el error de SINPE en espera. --- # Tilopay.updateOptions() > Actualiza parcialmente los parámetros enviados a Init() cuando cambian antes de cerrar el pago. - kind: sdk-method - status: stable - sdk_version: 2.1.1 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/sdk/reference/update-options Actualiza valores que ya se habían enviado en [`Tilopay.Init()`](/developers/sdk/reference/init) y que cambiaron durante el checkout — típicamente cuando el cliente edita sus datos, o cuando selecciona SINPE Móvil o Yappy y hay que agregar información que antes no aplicaba. > **Nota:** Es una actualización parcial. Se envían solo los campos que se quieren actualizar; no hay > que reenviar todo. ## Ningún campo es obligatorio en la llamada [#obligatorio] Ningún parámetro es obligatorio en `updateOptions()`. Lo que sí importa es que, antes de cerrar el pago, los datos que el método de pago necesita (por ejemplo `typeDni` y `dni` para SINPE Móvil, o `phoneYappy` para Yappy) se hayan enviado en `Init()` o en `updateOptions()`. ## Firma [#firma] ```js await Tilopay.updateOptions({ /* solo los campos que cambian */ }) ``` ## Llamada [#llamada] ```js const update = await Tilopay.updateOptions({ typeDni: 1, dni: "0707770777", billToFirstName: "Ana", billToLastName: "Rojas", }); ``` ## Parámetros [#parametros] URL a la que Tilopay notifica el resultado de pagos con SINPE Móvil y Yappy. Se pueden actualizar `typeDni`, `dni`, los campos `billTo*` (excepto `billToEmail`), los campos `shipTo*`, `capture`, `redirect`, `subscription` y `phoneYappy`. Tipo de identificación del cliente. Necesario para SINPE Móvil. Ver [tipos de identificación](#tipos-de-identificacion). Número de identificación del cliente. Necesario para SINPE Móvil. **Acepta con guiones y sin guiones.** Nombre del cliente. Apellidos del cliente. Dirección 1 del cliente. Dirección 2 del cliente. Ciudad. Provincia o estado. Código postal. País, ISO 3166-1 alpha-2. Teléfono del cliente. Nombre de quien recibe el envío. Apellidos de quien recibe el envío. Dirección 1 de envío. Dirección 2 de envío. Ciudad de envío. Provincia o estado de envío. Código postal de envío. País de envío, ISO 3166-1 alpha-2. Teléfono de envío. `0` autoriza; `1` autoriza y captura. URL donde se espera la respuesta final de la compra. `1` si el cliente quiere guardar su tarjeta en Tilopay; `0` si no. Teléfono Yappy. Necesario cuando el cliente paga con Yappy. > **Advertencia:** `billToEmail` no se puede actualizar. Una vez que `Init()` devolvió las tarjetas del > cliente, el correo no se puede cambiar por este método. ## Tipos de identificación [#tipos-de-identificacion] Aplica al parámetro `typeDni`, tanto acá como en `Tilopay.Init()`. En las máscaras, `#` es un carácter **numérico** y `&` es **alfanumérico**. Las longitudes no cuentan los guiones. | Código | Tipo | Formato | Longitud | |---|---|---|---| | 1 | Cédula de identidad | `0#-####-####` | 10 | | 2 | Cédula jurídica | `3-###-######` | 10 | | 3 | Gobierno central | `2-###-######` | 10 | | 4 | Institución autónoma | `4-###-######` | 10 | | 5 | Extranjero no residente | `9&&&&&&&&&&&&&&&&&&&` | 20 | | 6 | DIMEX | `1###########` | 12 | | 7 | DIDI | `5###########` | 12 | ## Respuesta [#respuesta] ```json { "message": "Success" } ``` `Success` cuando la actualización salió bien; la descripción del error en caso contrario. --- # API Bancario de Tilopay > Referencia del API Bancario (BaaS) de Tilopay generada desde su spec OpenAPI 3.0.3, versión 1.0.0. - kind: api-index - status: stable - api_version: 1.0.0 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/api-bancario Con nuestro API Bancario podés iniciar pagos (PIN y SINPE Móvil), consultar su estado, administrar tus cuentas y recibir webhooks de eventos de pago desde tus propios sistemas, siempre limitado a las cuentas que autoriza tu token de acceso. **Es un producto separado de la pasarela de pagos.** Corre en su propia infraestructura, con host, credenciales y autenticación propias. Si ya integrás nuestro API de adquirencia, el acceso a este se habilita por separado. En esta documentación encontrás los endpoints, modelos y flujos oficiales de la versión **1.0.0** del API Bancario. ## Qué permite hacer [#que-permite] **Pagos.** Creá un pago, consultalo por identificador, listalo por cuenta y buscalo por `payment_id`, `public_id` o `client_reference`; los métodos disponibles son `PIN` y `SINPE_MOVIL`. La creación solo admite dirección `OUT`; los pagos `IN` siguen en listados y webhooks. [Ver operaciones de pagos](/developers/api-bancario/pagos). **Cuentas.** Validá una cuenta destino antes de transferir, listá tus cuentas con o sin saldos, consultá el saldo de una cuenta y solicitá estados de cuenta de forma asincrónica. [Ver operaciones de cuentas](/developers/api-bancario/cuentas). **Webhooks.** Registrá tu destino HTTPS cifrado, consultá los eventos a los que podés suscribirte por método de pago y la estructura de datos que te enviamos en cada uno. [Ver operaciones de webhooks](/developers/api-bancario/webhooks). **Catálogos.** Tipos de persona de identificación de cliente por país. [Ver catálogos](/developers/api-bancario/catalogos). Además, ponemos a tu disposición `GET /api/public/v1/healthz` para chequeo de salud, y `GET /openapi.yaml` y `GET /docs` con la definición OpenAPI y la documentación interactiva directamente en el host del API. ## Entornos [#entornos] Hay dos entornos, con las mismas rutas y contratos. El de pruebas: ```text https://api-baas-sandbox.tilopay.com ``` El de producción es el mismo host sin el sufijo `-sandbox`: ```text https://api-baas.tilopay.com ``` Tilopay emite las credenciales de prueba a solicitud; coordiná el acceso con el contacto de tu comercio en Tilopay. Cuando estés listo, te entregamos las credenciales de producción al habilitar tu acceso. ## Artefactos legibles por máquina [#artefactos] Publicamos la definición OpenAPI completa del API Bancario, con CORS abierto, en dos formatos: - [openapi.json](/developers/api-bancario/openapi.json) - [openapi.yaml](/developers/api-bancario/openapi.yaml) Es independiente de la definición de nuestro API de adquirencia ([/developers/openapi.json](/developers/openapi.json)): son dos productos separados. ## Cómo obtener acceso [#acceso] El acceso es restringido y se otorga por solicitud, para operaciones en Costa Rica. Para conocer el producto y solicitarlo, visitá [baas.tilopay.com](https://baas.tilopay.com), indicando volumen mensual estimado, caso de uso y sistemas a integrar. ## Por dónde seguir [#siguiente] 1. [Autenticación](/developers/api-bancario/autenticacion) — login, intercambio de token y Bearer. 2. [Convenciones](/developers/api-bancario/convenciones) — envelope, correlación, reintentos seguros, paginación y fechas. 3. [Códigos de respuesta](/developers/api-bancario/errores) — catálogo completo de `response_code`. --- # Autenticación del API Bancario > Login, intercambio de token y uso del Bearer JWT en el API Bancario de Tilopay. - kind: concept - status: stable - api_version: 1.0.0 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/api-bancario/autenticacion El API Bancario usa un flujo de dos pasos: primero autenticás al cliente con correo y contraseña, después intercambiás el token resultante por un access token JWT que firma todas las demás llamadas. Los tres endpoints del grupo `Auth` son los únicos que **no** llevan `Authorization`. Todo el resto del API exige `Authorization: Bearer `. ## Paso 1 — Login [#login] ```http POST /api/public/v1/auth/login ``` Cuerpo requerido: `email` (formato email) y `password`. ```json { "email": "operaciones@comercio.com", "password": "••••••••" } ``` La respuesta `200` devuelve en `data`: | Campo | Tipo | Descripción | |---|---|---| | `gidp_id_token` | string | Token de identidad para el paso 2, válido por 1 hora y solo para el intercambio. | | `assignments` | array | Contextos disponibles del cliente. | Cada elemento de `assignments` trae `assignment_id`, `owner_type`, `owner_id`, `tenant_id`, `tenant_code`, `country_code`, `role`, `roles` y `status`. Elegí el `assignment_id` del contexto con el que vas a operar. ## Paso 2 — Intercambio de token [#exchange] ```http POST /api/public/v1/auth/token/exchange ``` Cuerpo requerido: `gidp_id_token` (el del paso 1) y `assignment_id` (el contexto elegido). ```json { "gidp_id_token": "eyJhbGciOi...", "assignment_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6" } ``` La respuesta `200` devuelve en `data`: | Campo | Tipo | Descripción | |---|---|---| | `token` | string | Access token JWT. | | `expires_in` | integer | Duración del token de acceso en segundos; leé `expires_in`, no asumás un valor fijo. | | `claims` | object | Contexto resuelto del token. | `claims` incluye `sub`, `subject_kind`, `user_type`, `tenant_id`, `owner_type`, `owner_id`, `roles`, `scopes`, `country_code`, `locale`, `channel`, `idp`, `idp_sub` e `idempotency_key`. `claims.idempotency_key` es un campo reservado que siempre viene vacío: ignoralo. La idempotencia va en el header `Idempotency-Key`. ## Paso 3 — Usar el Bearer [#bearer] El esquema de seguridad declarado es `BearerAuth`: HTTP bearer con formato JWT. ```http Authorization: Bearer ``` El contexto viaja **dentro** del token: no se envían `tenant_id`, `owner_id` ni `owner_type` como parámetros en las operaciones de negocio. El token acota por sí solo a qué cuentas y pagos podés acceder. Cuando el token está ausente, vencido o es inválido, la respuesta es `401` con `response_code: UNAUTHORIZED`. Si el token es válido pero el contexto no autoriza el recurso, es `403` con `FORBIDDEN`. No hay refresh token: para renovar, repetí login e intercambio (pasos 1 y 2) antes del vencimiento, recomendado al **80 % de `expires_in`**, o al recibir un `401`. ## Contraseñas [#password] ```http POST /api/public/v1/auth/request-set-password ``` Inicia el proceso de establecer o restablecer la contraseña del correo indicado. No requiere autenticación previa y responde siempre igual, exista o no la cuenta, para no revelar si un correo está registrado. ```json { "email": "operaciones@comercio.com" } ``` ## Límites de tasa [#limites-de-tasa] Actualmente aplican en autenticación y validación de cuentas. Al superarlos, se responde `429` (`TOO_MANY_REQUESTS`). Reintentá con espera exponencial. ## Acceso al sandbox [#sandbox] Tilopay emite las credenciales de prueba a solicitud; coordiná el acceso con el contacto de tu comercio en Tilopay. --- # Convenciones del API Bancario > Envelope de respuesta, correlación, reintentos seguros, paginación y formato de fechas del API Bancario. - kind: concept - status: stable - api_version: 1.0.0 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/api-bancario/convenciones Todas las operaciones del API Bancario comparten el mismo formato de respuesta, las mismas reglas de paginación y el mismo formato de fechas. Acá te explicamos esas reglas comunes. ## Envelope de respuesta [#envelope] Cada respuesta, exitosa o no, viaja en el mismo sobre: ```json { "success": true, "http_status_code": 200, "response_code": "OK", "message": "The request was processed successfully.", "correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "data": {} } ``` | Campo | Tipo | Descripción | |---|---|---| | `success` | boolean | `true` en las respuestas exitosas; `false` en las de error. | | `http_status_code` | integer | Repite el status HTTP en el cuerpo. | | `response_code` | string | Código del [catálogo de `response_code`](/developers/api-bancario/errores). | | `message` | string | Mensaje legible de la respuesta. | | `correlation_id` | string | Identificador de la llamada. | | `data` | object | Carga útil de la operación. | En las respuestas de error el sobre trae además `errors`, un objeto de detalle que puede incluir campos arbitrarios como `code`, `message` o `detail`. Ramificá tu lógica por `response_code`, no por el texto de `message`. ## Correlación [#correlacion] Enviá `X-Correlation-Id` en el request para propagar tu propio identificador; el valor vuelve como `correlation_id` en el sobre. Guardalo en tus logs: es el dato con el que soporte rastrea una llamada puntual. ## Reintentos seguros [#reintentos] Dos operaciones aceptan la cabecera `Idempotency-Key`: ```http POST /api/public/v1/transactions/payments POST /api/public/v1/accounts/statements ``` Reenviar la misma llave con el mismo cuerpo devuelve el resultado original en vez de crear un segundo registro, así un timeout de red se puede reintentar sin duplicar. Si reusás una llave con un cuerpo distinto, la respuesta es `409` con `response_code: IDEMPOTENCY_CONFLICT`. Generá una llave por intención de negocio (por ejemplo un UUID por orden), no una por reintento. El resto de las operaciones son consultas y se pueden repetir sin efectos adicionales. ## Paginación [#paginacion] El API usa dos esquemas según el recurso. **Cursor, en el listado de pagos.** `GET /api/public/v1/transactions/payments` acepta `limit` (por defecto 20, máximo 100) y `cursor`. La respuesta trae `pagination.next_cursor`: pasalo como `cursor` en el siguiente request. Cuando viene vacío u omitido, no hay más páginas. **Offset, en cuentas.** `GET /api/public/v1/accounts` y `GET /api/public/v1/accounts/balances` aceptan `limit` (1 a 100) y `offset` (desde 0), y devuelven `pagination` con `limit`, `offset` y `total`. ## Fechas y montos [#formatos] Los parámetros y campos de fecha usan RFC 3339, por ejemplo `2026-09-02T15:04:05Z`. Los filtros `date_from` y `date_to` del listado de pagos siguen ese mismo formato. ## Salud y documentación del host [#host] El propio host expone tres rutas de servicio: ```http GET /api/public/v1/healthz GET /openapi.yaml GET /docs ``` `healthz` sirve para chequeo de disponibilidad, `openapi.yaml` devuelve la definición OpenAPI y `/docs` la documentación interactiva. En este portal también la publicamos en [openapi.json](/developers/api-bancario/openapi.json) y [openapi.yaml](/developers/api-bancario/openapi.yaml). ## Identificador público [#public-id] `public_id` llega como número en webhooks y como texto en REST; es el mismo identificador. **Tratalo siempre como texto.** ## Límites de tasa [#limites-de-tasa] Hoy aplican en autenticación y validación de cuentas. Al superarse se responde `429` (`TOO_MANY_REQUESTS`); reintentá con espera exponencial. --- # Pagos del API Bancario > Operaciones de pagos del API Bancario: crear, consultar, listar y buscar pagos PIN y SINPE Móvil. - kind: api-operation - status: stable - api_version: 1.0.0 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/api-bancario/pagos El grupo `Payments` cubre el ciclo completo de un pago: crearlo, consultarlo por identificador, listarlo con filtros y buscarlo por cualquiera de sus referencias. ```http POST /api/public/v1/transactions/payments GET /api/public/v1/transactions/payments GET /api/public/v1/transactions/payments/{payment_id} POST /api/public/v1/transactions/payments/search ``` ## Reglas del recurso [#reglas] **Métodos.** `payment_method_code` admite `PIN` y `SINPE_MOVIL`. **Dirección.** Al crear, `direction` solo admite `OUT` (salida); los pagos `IN` (entrada) siguen existiendo en listados y webhooks. **Cuenta destino.** se identifica por `IBAN` o por `PHONE`, según el método. Validala antes de transferir con la [validación de cuentas](/developers/api-bancario/cuentas#operaciones). **Referencia propia.** `client_reference` es tu identificador del pago y es único por tenant: dos pagos del mismo cliente no pueden compartirlo. Sirve para buscar el pago sin guardar el `payment_id`. **Reintentos seguros.** La creación acepta `Idempotency-Key`; reenviar la misma llave con el mismo cuerpo devuelve el pago original en vez de crear otro. Ver [reintentos seguros](/developers/api-bancario/convenciones#reintentos). ## Estados [#estados] Un pago recorre cinco estados: `pending`, `processing`, `confirmed`, `posted` y `failed`. La reversión **no es un estado**: un pago revertido sigue en `posted` y se reconoce por `result: reversed` y `has_reversal: true`, además del evento [`payment.reversed`](/developers/api-bancario/webhooks). Consultá siempre esos dos campos antes de dar un pago por definitivo. ## Operaciones [#operaciones] ### Listar pagos del cliente [#get-transactions-payments] ```http GET /api/public/v1/transactions/payments ``` Host: `https://api-baas-sandbox.tilopay.com` — requiere `Authorization: Bearer `. Lista REST simple de los pagos de una cuenta propia (IBAN). Los filtros son parámetros de consulta. La titularidad (`tenant_id`, `owner_type`, `owner_id`) se deriva del token de acceso; no enviés filtros de titularidad. **Identificación de la cuenta (requerida):** `type` + `value` (esquema de identificación + valor, ej. `IBAN` + el IBAN). No es la clasificación interna de la cuenta. La paginación es por cursor (`limit`, `cursor`). Límite por defecto 20 (máximo 100). `status` en la respuesta y como filtro usa el catálogo público en minúsculas (`pending`, `processing`, `confirmed`, `posted`, `failed`). Mismos valores que los webhooks. REST también devuelve `status_detail` (nombre operativo en mayúsculas). Cada ítem incluye un `result` consolidado (`succeeded`, `failed`, `reversed`, `pending`) para conciliar cuando se perdió un webhook. `status` es solo el catálogo de procesamiento/ciclo de vida y no cambia a `failed` cuando un pago registrado se revierte después: usá `result=reversed` y `has_reversal=true` (webhook `payment.reversed`). `error` es `null` cuando no hay información de fallo; es un objeto solo cuando `domain` / `platform` está presente (`result` es `failed` o `reversed`), misma forma que `payment.error` del webhook `payment.failed`. `source` / `destination` usan `null` para `account`, `name` e `identification` desconocidos; los valores de cuenta son solo IBAN o PHONE (nunca UUID internos de cuenta). En pagos PIN, `identification.number` es el número público enviado por el comercio (sin guiones SINPE); los pagos antiguos aún pueden mostrar la forma SINPE con guiones. **Parámetros** | Parámetro | En | Tipo | Obligatorio | Descripción | |---|---|---|---|---| | `X-Correlation-Id` | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta. Se devuelve como `correlation_id` en el sobre de respuesta. Si lo omitís, la API genera uno y igual lo devuelve. | | `type` | query | string | sí | **Esquema de identificación** de la cuenta (ej. `IBAN`). **No** es la clasificación interna de la cuenta (ej. operativa). Values: IBAN | | `value` | query | string | sí | Valor del identificador de la cuenta (IBAN). Los espacios se ignoran. | | `status` | query | string | no | Filtro opcional por estado del pago. El catálogo público es en minúsculas: `pending`, `processing`, `confirmed`, `posted`, `failed`. Se aceptan alias en mayúsculas de los mismos valores. Valores históricos como `INITIATED` equivalen a `pending`. Values: pending, processing, confirmed, posted, failed | | `date_from` | query | string (date-time) | no | Límite inferior inclusivo para `created_at`. RFC 3339 (UTC `Z` u offset; fracciones de segundo opcionales). | | `date_to` | query | string (date-time) | no | Límite superior inclusivo para `created_at`. RFC 3339 (UTC `Z` u offset; fracciones de segundo opcionales). | | `client_reference` | query | string | no | Filtro por la referencia de cliente del comercio (coincidencia exacta con el valor enviado al crear el pago). | | `currency` | query | string | no | Filtro por moneda del pago (ISO 4217, ej. CRC). | | `payment_method_code` | query | string | no | Filtro por código público del método de pago. Values: PIN, SINPE_MOVIL | | `direction` | query | string | no | Filtro por dirección del pago. Acepta los valores públicos `OUT`/`IN` o `PAYOUT`/`PAYIN` (se normalizan internamente a `payout`/`payin`). Values: OUT, IN, PAYOUT, PAYIN | | `limit` | query | integer | no | Tamaño de página (por defecto 20, máximo 100). | | `cursor` | query | string | no | Cursor opaco de la `pagination.next_cursor` de una respuesta anterior. | **200** — La solicitud se procesó correctamente. Campos de `data`: | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `schema_version` | string | sí | Mismo valor que el `schema_version` del sobre del webhook (`1.0.0`). | | `items` | array | sí | — | | `items[].schema_version` | string | sí | Versión del contrato de lectura de pagos. Mismo valor que el `schema_version` del sobre del webhook (`1.0.0`) para `payment.succeeded` / `payment.failed`. | | `items[].payment_id` | string (uuid) | sí | UUID del pago devuelto al crearlo. Llave del pago para el comercio en `GET /transactions/payments/{payment_id}` y en la búsqueda. No es un id interno de cuenta. | | `items[].public_id` | string | no | Identificador público numérico del pago devuelto al crearlo. `null` si aún no se asigna. No es un UUID interno de cuenta. Es el mismo identificador: número en webhooks y texto en REST. Tratalo siempre como texto. Puede ser null. | | `items[].type` | string | sí | Tipo de pago derivado de la dirección (`PAYIN` / `PAYOUT`). | | `items[].payment_method_code` | string | sí | Catálogo público de métodos de pago (`PIN`, `SINPE_MOVIL`). Mismos valores que en los webhooks. Values: PIN, SINPE_MOVIL | | `items[].status` | string | sí | Catálogo público de estados del pago. Siempre en minúsculas. Mismos valores en REST (crear, listar, obtener) y en webhooks (`payment.status`). Los estados internos del ciclo de vida se consolidan: - `pending`: iniciado, validado, aceptado - `processing`: procesando, pendiente de procesamiento, registrando - `confirmed`: confirmado por el riel, aún no registrado en el ledger - `posted`: registrado en el ledger (se mantiene `posted` tras un reverso posterior) - `failed`: fallido, rechazado, posting_failed, cancelado, expirado Un reverso **no** es un estado. Usá `result=reversed` / `has_reversal=true` en REST y el webhook `payment.reversed`. El detalle operativo queda en `status_detail` (nombre interno en mayúsculas) en crear/listar/obtener de REST. El webhook `payment.failed` usa `error.platform.code` para distinguir fallos de registro de rechazos del proveedor. Values: pending, processing, confirmed, posted, failed | | `items[].status_detail` | string | no | Estado operativo (interno) en mayúsculas, ej. `VALIDATED`, `POSTED`, `POSTING_FAILED`. Complemento del catálogo público `status`. Independiente de `result` (`posted` es el hito de débito/registro, no el éxito del proveedor). | | `items[].result` | string | sí | Resultado de negocio consolidado para conciliación (respaldo de los webhooks). Independiente del `status` de procesamiento. Se deriva así: `reversed` cuando `has_reversal` es true (prioridad más alta); `succeeded` cuando `succeeded_at` está presente y no hay reverso; `failed` cuando el estado de procesamiento es `failed` o `posting_failed`; si no, `pending`. Un pago registrado (posted) que luego se revirtió tiene `status=posted` y `result=reversed`. Values: succeeded, failed, reversed, pending | | `items[].succeeded_at` | string (date-time) | no | Marca de tiempo de confirmación de éxito del proveedor (RFC 3339 UTC, precisión de segundos, `Z`). Null mientras el pago ya pueda estar `posted` internamente pero el proveedor no haya confirmado el éxito. Puede ser null. | | `items[].has_reversal` | boolean | sí | True cuando se aplicó un reverso. Independiente de `status`. Se correlaciona con el webhook `payment.reversed`. | | `items[].reversed_at` | string (date-time) | no | Cuándo se aplicó el reverso. Null cuando `has_reversal` es false. Puede ser null. | | `items[].created_at` | string (date-time) | no | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `items[].updated_at` | string (date-time) | no | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `items[].amount` | object | no | Misma forma monetaria que la creación de pago (`PaymentAmount`). | | `items[].amount.amount` | string | sí | — | | `items[].amount.currency` | string | sí | — | | `items[].source` | object | no | Parte del pago en las lecturas del API. Los campos anidados siempre están presentes: `null` cuando el valor se desconoce. `account` es un identificador público (`IBAN` o `PHONE`); nunca se devuelven UUID internos de cuenta. | | `items[].source.account` | object | sí | Identificador público de la cuenta (`type` + `value`). `null` cuando el IBAN o el teléfono no pueden resolverse. Nunca un UUID interno de cuenta. Puede ser null. | | `items[].source.name` | string | sí | Nombre de la parte según los datos de procesamiento cuando está disponible; si no, `null`. Puede ser null. | | `items[].source.identification` | object | sí | Identificación de la parte (clave de catálogo `type` + `number`). Objeto solo cuando al menos un campo se conoce; si no, `null`. No expone los códigos internos de tipo de SINPE (`0`–`9`); los tipos sin equivalencia se omiten (`type: null`). `number` es el valor público enviado por el comercio (dígitos, sin guiones SINPE). Los pagos históricos aún pueden devolver la forma de visualización SINPE con guiones. Puede ser null. | | `items[].destination` | object | no | Parte del pago en las lecturas del API. Los campos anidados siempre están presentes: `null` cuando el valor se desconoce. `account` es un identificador público (`IBAN` o `PHONE`); nunca se devuelven UUID internos de cuenta. | | `items[].destination.account` | object | sí | Identificador público de la cuenta (`type` + `value`). `null` cuando el IBAN o el teléfono no pueden resolverse. Nunca un UUID interno de cuenta. Puede ser null. | | `items[].destination.name` | string | sí | Nombre de la parte según los datos de procesamiento cuando está disponible; si no, `null`. Puede ser null. | | `items[].destination.identification` | object | sí | Identificación de la parte (clave de catálogo `type` + `number`). Objeto solo cuando al menos un campo se conoce; si no, `null`. No expone los códigos internos de tipo de SINPE (`0`–`9`); los tipos sin equivalencia se omiten (`type: null`). `number` es el valor público enviado por el comercio (dígitos, sin guiones SINPE). Los pagos históricos aún pueden devolver la forma de visualización SINPE con guiones. Puede ser null. | | `items[].client_reference` | string | no | Referencia del comercio enviada al crear el pago (estable después del procesamiento). Mismo campo que `payment.client_reference` del webhook. | | `items[].external_reference` | string | no | Rail/SINPE transaction id. Same field, location, and meaning as webhook `payment.external_reference` on `payment.succeeded` / `payment.failed` Sibling of `client_reference`. `null` if none. Puede ser null. | | `items[].provider` | object | no | Foto compartida del proveedor en las lecturas REST de pagos y en los sobres de webhook. La referencia del riel solo está en `payment.external_reference`, no se duplica aquí. Los `provider_status_*` coinciden con `rejection.reason_code` / `message` / `code` del webhook cuando el proveedor rechazó la operación. `null` cuando no hay rechazo. | | `items[].provider.correlation_id` | string | sí | Provider transaction correlation identifier. Sent to SINPE as the correlation id. Not `channel_reference` (e.g. `MOBILE_APP`). Distinct from webhook `event.correlation_id` (HTTP request id for this delivery). `null` when unknown. Puede ser null. | | `items[].provider.occurred_at` | string (date-time) | sí | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `items[].provider.provider_status_code` | string | sí | Motivo/código crudo del proveedor (ej. `31`). Mismo significado que `rejection.reason_code` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `items[].provider.provider_status_desc` | string | sí | Texto Motivo del proveedor (prefiere Detalle). Mismo significado que `rejection.message` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `items[].provider.provider_status_semantic` | string | sí | Semántica normalizada de la plataforma (ej. `ACCOUNT_BLOCKED`). Mismo significado que `rejection.code` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `items[].error` | object | no | Siempre presente. `null` cuando no hay información de fallo (`succeeded`, `pending`, o failed/reversed sin taxonomía). El objeto usa la misma forma `domain` / `platform` que el webhook `payment.failed`. Puede ser null. | | `items[].error.domain` | string | sí | Mismo catálogo que `payment.error.domain` del webhook. Values: provider_rejection, platform_validation, platform_posting, platform_infra, platform_reversal | | `items[].error.platform` | object | sí | — | | `pagination` | object | no | Paginación por cursor. Pasá next_cursor como cursor en la siguiente solicitud. | | `pagination.next_cursor` | string | no | Cursor opaco de la página siguiente; se omite o va vacío cuando no hay más páginas | | `pagination.limit` | integer | no | Tamaño de página aplicado a esta respuesta | **Ejemplo de respuesta** ```json { "success": true, "http_status_code": 200, "response_code": "OK", "message": "The request was processed successfully.", "correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "data": { "schema_version": "1.0.0", "items": [ { "schema_version": "1.0.0", "payment_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d", "public_id": "10234", "type": "PAYOUT", "payment_method_code": "PIN", "status": "posted", "status_detail": "POSTED", "result": "succeeded", "succeeded_at": "2026-01-15T12:00:00Z", "has_reversal": false, "reversed_at": null, "created_at": "2026-01-15T12:00:00Z", "updated_at": "2026-01-15T12:00:00Z", "amount": { "amount": "1000.00", "currency": "CRC", "fees": "0.00", "taxes": "0.00" }, "source": { "account": { "type": "IBAN", "value": "CR26036900101010588061", "currency": "CRC" }, "name": "María González", "identification": { "type": "cedula", "number": "0205620043" } }, "destination": { "account": { "type": "IBAN", "value": "CR16010400000000000031", "currency": "CRC" }, "name": "Juan Perez", "identification": { "type": "cedula", "number": "0101010101" } }, "client_reference": "INV-1001", "external_reference": "SINPE-20260115-000123", "provider": { "correlation_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "occurred_at": "2026-01-15T12:00:00Z", "provider_status_code": "00", "provider_status_desc": "Aprobada", "provider_status_semantic": "SUCCESS" }, "error": null } ], "pagination": { "next_cursor": "", "limit": 20 } } } ``` **Respuestas de error** | HTTP | response_code | Descripción | |---|---|---| | 400 | `INVALID_REQUEST` | Invalid request. Check the required fields and try again. | | 401 | `UNAUTHORIZED` | Unauthorized. Verify your session or credentials. | | 403 | `FORBIDDEN` | You do not have permission to perform this action. | | 403 | `ACCOUNT_ACCESS_DENIED` | The actor does not have access to the requested account. | | 500 | `INTERNAL_ERROR` | An unexpected error occurred. Please try again later. | | 502 | `PROVIDER_ERROR` | Unable to complete the request with the payment provider. Please try again later. | | 503 | `SERVICE_UNAVAILABLE` | A required service is temporarily unavailable. Please try again later. | ### Crear pago [#post-transactions-payments] ```http POST /api/public/v1/transactions/payments ``` Host: `https://api-baas-sandbox.tilopay.com` — requiere `Authorization: Bearer `. Crea un pago desde una cuenta origen interna autorizada. El procesamiento puede ser asíncrono; HTTP 201 no implica que el pago esté finalizado. `source.identification.number` y `destination.identification.number` se guardan en forma pública (los dígitos enviados, sin guiones SINPE) y se devuelven en las lecturas posteriores. La forma con guiones de SINPE solo se usa internamente y no es el contrato público. Idempotency-Key es opcional; si se omite, cada solicitud se trata como un intento nuevo. Un `client_reference` repetido devuelve 409 PAYMENT_DUPLICATE cuando un pago en curso o completado ya lo usa; un pago previo `failed` (o rechazado/cancelado/expirado) no bloquea reintentar con el mismo `client_reference`. Si se envía Idempotency-Key, la misma clave con el mismo cuerpo repite la respuesta anterior; un cuerpo distinto con la misma clave devuelve 409 IDEMPOTENCY_CONFLICT. No hay doble control en la creación de pagos del API: el pago se procesa directamente si el token, los permisos y los datos son válidos. Solo se admite direction OUT. Aplican límites por transacción, diarios y mensuales, en monto y cantidad. Si se supera alguno, el procesamiento falla y el evento payment.failed notifica el resultado. **Parámetros** | Parámetro | En | Tipo | Obligatorio | Descripción | |---|---|---|---|---| | `X-Correlation-Id` | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta. Se devuelve como `correlation_id` en el sobre de respuesta. Si lo omitís, la API genera uno y igual lo devuelve. | | `Idempotency-Key` | header | string | no | Clave opaca opcional para reintentos seguros. Si la omitís, cada llamada es un intento nuevo (los duplicados se detectan por client_reference en pagos en curso o completados). Reutilizar la clave con un cuerpo distinto devuelve 409. | **Cuerpo del request** | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `payment_method_code` | string | sí | Catálogo público de métodos de pago (`PIN`, `SINPE_MOVIL`). Values: PIN, SINPE_MOVIL | | `direction` | string | sí | La creación solo acepta OUT (salida). Los pagos IN siguen disponibles en listados y webhooks. Values: OUT | | `country_code` | string | no | País operativo cuando aplica multi-país | | `amount` | object | sí | — | | `amount.amount` | string | sí | Monto como texto decimal con exactamente 2 decimales (ej. "1000.00"). | | `amount.currency` | string | sí | Moneda ISO 4217 del pago. Values: CRC, USD | | `source` | object | sí | — | | `source.account` | object | sí | — | | `source.account.type` | string | sí | **Esquema de identificación** de la cuenta. Aquí solo se admite `IBAN`. No es la clasificación interna de la cuenta (ej. operativa). Values: IBAN | | `source.account.value` | string | sí | IBAN (se permiten espacios; se normaliza en el servidor) | | `source.name` | string | sí | Nombre del titular | | `source.identification` | object | sí | Identificación del beneficiario al crear un pago. `type` usa las claves del catálogo de identificación de la plataforma (ej. `cedula`, `juridica`, `dimex`). Mismo vocabulario que `holder.id_type` de `POST /accounts/validate`. `number` es la identificación pública (dígitos, sin guiones SINPE). La plataforma puede reformatearlo internamente para SINPE; esa forma interna no se devuelve en las lecturas públicas de pagos. Para SINPE_MOVIL, la validación de cuenta puede devolver `unknown` porque la consulta del monedero no expone el tipo de identificación; no asumás un tipo confirmado. | | `source.identification.type` | string | no | Clave del catálogo de identificación (minúsculas), ej. `cedula`, `juridica`. Puede copiarse de `holder.id_type` después de validar la cuenta. Para SINPE_MOVIL ese valor puede ser `unknown` (limitación esperada, no un error). Values: cedula, juridica, dimex, gobierno, institucion_autonoma, didi, pasaporte | | `source.identification.number` | string | no | Número de identificación público tal como lo envió el comercio. Solo dígitos; no enviés la forma con guiones de SINPE (ej. `01-1234-3005`) ni tratés este campo como la forma interna de visualización SINPE. Los tipos admitidos incluyen `cedula`, `juridica`, `dimex`, `gobierno`, `institucion_autonoma`, `didi` y `pasaporte`. | | `destination` | object | sí | — | | `destination.account` | object | sí | — | | `destination.account.type` | string | sí | **Esquema de identificación** de la cuenta del beneficiario (`IBAN` para PIN, `PHONE` para SINPE_MOVIL). No es la clasificación interna de la cuenta. Values: IBAN, PHONE | | `destination.account.value` | string | sí | Cuando `type` es `PHONE` (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777"). Patrón para `PHONE`: `^\d{8}$`. | | `destination.name` | string | sí | Nombre del beneficiario | | `destination.identification` | object | sí | Identificación del beneficiario al crear un pago. `type` usa las claves del catálogo de identificación de la plataforma (ej. `cedula`, `juridica`, `dimex`). Mismo vocabulario que `holder.id_type` de `POST /accounts/validate`. `number` es la identificación pública (dígitos, sin guiones SINPE). La plataforma puede reformatearlo internamente para SINPE; esa forma interna no se devuelve en las lecturas públicas de pagos. Para SINPE_MOVIL, la validación de cuenta puede devolver `unknown` porque la consulta del monedero no expone el tipo de identificación; no asumás un tipo confirmado. | | `destination.identification.type` | string | no | Clave del catálogo de identificación (minúsculas), ej. `cedula`, `juridica`. Puede copiarse de `holder.id_type` después de validar la cuenta. Para SINPE_MOVIL ese valor puede ser `unknown` (limitación esperada, no un error). Values: cedula, juridica, dimex, gobierno, institucion_autonoma, didi, pasaporte | | `destination.identification.number` | string | no | Número de identificación público tal como lo envió el comercio. Solo dígitos; no enviés la forma con guiones de SINPE (ej. `01-1234-3005`) ni tratés este campo como la forma interna de visualización SINPE. Los tipos admitidos incluyen `cedula`, `juridica`, `dimex`, `gobierno`, `institucion_autonoma`, `didi` y `pasaporte`. | | `detail_reference` | string | sí | Descripción operativa / transaccional que se guarda en el pago | | `client_reference` | string | no | Referencia funcional del comercio. Única por comercio entre pagos en curso y completados; un intento fallido puede reintentarse con el mismo valor. | | `channel_reference` | string | no | — | | `originator` | object | no | Información opcional del ordenante (Ultimate Debtor / Travel Rule). Solo informativa en esta versión; no se aplica validación. Se guarda en los metadatos del pago cuando se envía. Puede ser null. | | `originator.company` | object | no | Puede ser null. | | `originator.company.legal_name` | string | no | — | | `originator.company.id_type` | string | no | — | | `originator.company.id_number` | string | no | — | | `originator.customer` | object | no | Puede ser null. | | `originator.customer.name` | string | no | — | | `originator.customer.id_type` | string | no | — | | `originator.customer.id_number` | string | no | — | **Ejemplo de request** ```json { "payment_method_code": "PIN", "direction": "OUT", "country_code": "CR", "amount": { "amount": "1000.00", "currency": "CRC" }, "source": { "account": { "type": "IBAN", "value": "CR26036900101010588061" }, "name": "María González", "identification": { "type": "cedula", "number": "0205620043" } }, "destination": { "account": { "type": "IBAN", "value": "CR16010400000000000031" }, "name": "Juan Perez", "identification": { "type": "cedula", "number": "0101010101" } }, "detail_reference": "Pago factura 1001", "client_reference": "INV-1001", "channel_reference": "MOBILE_APP" } ``` **201** — El recurso se creó correctamente. Campos de `data`: | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `payment_id` | string (uuid) | no | UUID interno del pago | | `public_id` | string | no | Identificador público numérico del pago Es el mismo identificador: número en webhooks y texto en REST. Tratalo siempre como texto. | | `status` | string | no | Catálogo público de estados del pago. Siempre en minúsculas. Mismos valores en REST (crear, listar, obtener) y en webhooks (`payment.status`). Los estados internos del ciclo de vida se consolidan: - `pending`: iniciado, validado, aceptado - `processing`: procesando, pendiente de procesamiento, registrando - `confirmed`: confirmado por el riel, aún no registrado en el ledger - `posted`: registrado en el ledger (se mantiene `posted` tras un reverso posterior) - `failed`: fallido, rechazado, posting_failed, cancelado, expirado Un reverso **no** es un estado. Usá `result=reversed` / `has_reversal=true` en REST y el webhook `payment.reversed`. El detalle operativo queda en `status_detail` (nombre interno en mayúsculas) en crear/listar/obtener de REST. El webhook `payment.failed` usa `error.platform.code` para distinguir fallos de registro de rechazos del proveedor. Values: pending, processing, confirmed, posted, failed | | `status_detail` | string | no | Detalle operativo del estado (ej. PROCESSING) | | `payment_method_code` | string | no | Catálogo público de métodos de pago (`PIN`, `SINPE_MOVIL`). Values: PIN, SINPE_MOVIL | | `created_at` | string (date-time) | no | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | **Ejemplo de respuesta** ```json { "success": true, "http_status_code": 201, "response_code": "CREATED", "message": "The resource was created successfully.", "correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "data": { "payment_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d", "public_id": "10234", "status": "pending", "status_detail": "PROCESSING", "payment_method_code": "PIN", "created_at": "2026-01-15T12:00:00Z" } } ``` **Respuestas de error** | HTTP | response_code | Descripción | |---|---|---| | 400 | `PAYMENT_INVALID_PAYLOAD` | Invalid payment request payload. | | 400 | `INVALID_PAYMENT_METHOD` | Invalid or unsupported payment method. | | 400 | `INVALID_ACCOUNT_TYPE` | Unsupported or invalid account type. | | 400 | `ACCOUNT_INVALID` | The account is invalid or not enabled for the service. | | 400 | `ACCOUNT_HOLDER_MISMATCH` | Account holder does not match the provided identification or name. | | 401 | `UNAUTHORIZED` | Unauthorized. Verify your session or credentials. | | 403 | `FORBIDDEN` | You do not have permission to perform this action. | | 403 | `ACCOUNT_ACCESS_DENIED` | The actor does not have access to the requested account. | | 404 | `ACCOUNT_NOT_FOUND` | Account not found. | | 409 | `IDEMPOTENCY_CONFLICT` | Idempotency conflict: the same Idempotency-Key was reused with a different request body, or a previous request is still in progress. | | 409 | `PAYMENT_DUPLICATE` | An in-flight or completed payment with this client_reference already exists. | | 409 | `CONFLICT` | The request conflicts with the current state. | | 422 | `INSUFFICIENT_FUNDS` | Insufficient funds to complete the payment. | | 422 | `LIMIT_EXCEEDED` | A transaction or accumulation limit was exceeded. | | 422 | `UNPROCESSABLE_ENTITY` | The request is well-formed but cannot be processed due to business rules. | | 500 | `INTERNAL_ERROR` | An unexpected error occurred. Please try again later. | | 502 | `PROVIDER_ERROR` | Unable to complete the request with the payment provider. Please try again later. | | 503 | `SERVICE_UNAVAILABLE` | A required service is temporarily unavailable. Please try again later. | ### Buscar pago por identificador [#post-transactions-payments-search] ```http POST /api/public/v1/transactions/payments/search ``` Host: `https://api-baas-sandbox.tilopay.com` — requiere `Authorization: Bearer `. Busca un solo pago dentro de la cuenta del cliente indicada, por exactamente uno de: - `payment_id` (UUID interno) - `public_id` (identificador público numérico) - `client_reference` (referencia del comercio enviada al crear) Enviar más de un identificador devuelve `400`. La respuesta tiene la misma forma que la consulta por id (`schema_version`, `external_reference` a nivel de pago, objeto `provider` compartido, `provider.provider_status_*`, `error` alineado con el webhook). Mismo contrato público que `GET /transactions/payments`, incluido el `identification.number` público de los pagos PIN. Si varios pagos comparten un `client_reference` (intento fallido más reintento), se devuelve el pago en curso o completado cuando existe. **Parámetros** | Parámetro | En | Tipo | Obligatorio | Descripción | |---|---|---|---|---| | `X-Correlation-Id` | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta. Se devuelve como `correlation_id` en el sobre de respuesta. Si lo omitís, la API genera uno y igual lo devuelve. | **Cuerpo del request** | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `account` | object | sí | — | | `account.type` | string | sí | **Esquema de identificación** de la cuenta (ej. `IBAN`, `PHONE`). No es la clasificación interna de la cuenta (ej. operativa). Values: IBAN, PHONE | | `account.value` | string | sí | Cuando `type` es `PHONE` (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777"). | | `account.currency` | string | no | Moneda opcional de la cuenta en las respuestas. | | `payment_id` | string (uuid) | no | UUID interno del pago. | | `public_id` | string | no | Identificador público numérico del pago. Es el mismo identificador: número en webhooks y texto en REST. Tratalo siempre como texto. | | `client_reference` | string | no | Referencia del comercio enviada al crear el pago. | **Ejemplo de request** — byPaymentId ```json { "account": { "type": "IBAN", "value": "CR08036900101010933608" }, "payment_id": "11111111-1111-1111-1111-111111111111" } ``` **Ejemplo de request** — byPublicId ```json { "account": { "type": "IBAN", "value": "CR08036900101010933608" }, "public_id": "134729" } ``` **Ejemplo de request** — byClientReference ```json { "account": { "type": "IBAN", "value": "CR08036900101010933608" }, "client_reference": "INV-01082" } ``` **200** — La solicitud se procesó correctamente. Campos de `data`: | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `schema_version` | string | sí | Versión del contrato de lectura de pagos. Mismo valor que el `schema_version` del sobre del webhook (`1.0.0`) para `payment.succeeded` / `payment.failed`. | | `payment_id` | string (uuid) | sí | UUID del pago devuelto al crearlo. Llave del pago para el comercio en `GET /transactions/payments/{payment_id}` y en la búsqueda. No es un id interno de cuenta. | | `public_id` | string | no | Identificador público numérico del pago devuelto al crearlo. `null` si aún no se asigna. No es un UUID interno de cuenta. Es el mismo identificador: número en webhooks y texto en REST. Tratalo siempre como texto. Puede ser null. | | `type` | string | sí | Tipo de pago derivado de la dirección (`PAYIN` / `PAYOUT`). | | `payment_method_code` | string | sí | Catálogo público de métodos de pago (`PIN`, `SINPE_MOVIL`). Mismos valores que en los webhooks. Values: PIN, SINPE_MOVIL | | `status` | string | sí | Catálogo público de estados del pago. Siempre en minúsculas. Mismos valores en REST (crear, listar, obtener) y en webhooks (`payment.status`). Los estados internos del ciclo de vida se consolidan: - `pending`: iniciado, validado, aceptado - `processing`: procesando, pendiente de procesamiento, registrando - `confirmed`: confirmado por el riel, aún no registrado en el ledger - `posted`: registrado en el ledger (se mantiene `posted` tras un reverso posterior) - `failed`: fallido, rechazado, posting_failed, cancelado, expirado Un reverso **no** es un estado. Usá `result=reversed` / `has_reversal=true` en REST y el webhook `payment.reversed`. El detalle operativo queda en `status_detail` (nombre interno en mayúsculas) en crear/listar/obtener de REST. El webhook `payment.failed` usa `error.platform.code` para distinguir fallos de registro de rechazos del proveedor. Values: pending, processing, confirmed, posted, failed | | `status_detail` | string | no | Estado operativo (interno) en mayúsculas, ej. `VALIDATED`, `POSTED`, `POSTING_FAILED`. Complemento del catálogo público `status`. Independiente de `result` (`posted` es el hito de débito/registro, no el éxito del proveedor). | | `result` | string | sí | Resultado de negocio consolidado para conciliación (respaldo de los webhooks). Independiente del `status` de procesamiento. Se deriva así: `reversed` cuando `has_reversal` es true (prioridad más alta); `succeeded` cuando `succeeded_at` está presente y no hay reverso; `failed` cuando el estado de procesamiento es `failed` o `posting_failed`; si no, `pending`. Un pago registrado (posted) que luego se revirtió tiene `status=posted` y `result=reversed`. Values: succeeded, failed, reversed, pending | | `succeeded_at` | string (date-time) | no | Marca de tiempo de confirmación de éxito del proveedor (RFC 3339 UTC, precisión de segundos, `Z`). Null mientras el pago ya pueda estar `posted` internamente pero el proveedor no haya confirmado el éxito. Puede ser null. | | `has_reversal` | boolean | sí | True cuando se aplicó un reverso. Independiente de `status`. Se correlaciona con el webhook `payment.reversed`. | | `reversed_at` | string (date-time) | no | Cuándo se aplicó el reverso. Null cuando `has_reversal` es false. Puede ser null. | | `created_at` | string (date-time) | no | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `updated_at` | string (date-time) | no | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `amount` | object | no | Misma forma monetaria que la creación de pago (`PaymentAmount`). | | `amount.amount` | string | sí | — | | `amount.currency` | string | sí | — | | `source` | object | no | Parte del pago en las lecturas del API. Los campos anidados siempre están presentes: `null` cuando el valor se desconoce. `account` es un identificador público (`IBAN` o `PHONE`); nunca se devuelven UUID internos de cuenta. | | `source.account` | object | sí | Identificador público de la cuenta (`type` + `value`). `null` cuando el IBAN o el teléfono no pueden resolverse. Nunca un UUID interno de cuenta. Puede ser null. | | `source.account.type` | string | sí | **Esquema de identificación** de la cuenta (ej. `IBAN`, `PHONE`). No es la clasificación interna de la cuenta (ej. operativa). Values: IBAN, PHONE | | `source.account.value` | string | sí | Cuando `type` es `PHONE` (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777"). | | `source.account.currency` | string | no | Moneda opcional de la cuenta en las respuestas. | | `source.name` | string | sí | Nombre de la parte según los datos de procesamiento cuando está disponible; si no, `null`. Puede ser null. | | `source.identification` | object | sí | Identificación de la parte (clave de catálogo `type` + `number`). Objeto solo cuando al menos un campo se conoce; si no, `null`. No expone los códigos internos de tipo de SINPE (`0`–`9`); los tipos sin equivalencia se omiten (`type: null`). `number` es el valor público enviado por el comercio (dígitos, sin guiones SINPE). Los pagos históricos aún pueden devolver la forma de visualización SINPE con guiones. Puede ser null. | | `source.identification.type` | string | no | Clave del catálogo de identificación (ej. `cedula`, `juridica`). `null` cuando se desconoce. Puede ser null. | | `source.identification.number` | string | no | Número de identificación público. Los pagos PIN nuevos devuelven el valor enviado por el comercio (dígitos, sin guiones SINPE). Los pagos históricos aún pueden devolver la forma de visualización SINPE (con guiones, posiblemente con relleno). Puede ser null. | | `destination` | object | no | Parte del pago en las lecturas del API. Los campos anidados siempre están presentes: `null` cuando el valor se desconoce. `account` es un identificador público (`IBAN` o `PHONE`); nunca se devuelven UUID internos de cuenta. | | `destination.account` | object | sí | Identificador público de la cuenta (`type` + `value`). `null` cuando el IBAN o el teléfono no pueden resolverse. Nunca un UUID interno de cuenta. Puede ser null. | | `destination.account.type` | string | sí | **Esquema de identificación** de la cuenta (ej. `IBAN`, `PHONE`). No es la clasificación interna de la cuenta (ej. operativa). Values: IBAN, PHONE | | `destination.account.value` | string | sí | Cuando `type` es `PHONE` (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777"). | | `destination.account.currency` | string | no | Moneda opcional de la cuenta en las respuestas. | | `destination.name` | string | sí | Nombre de la parte según los datos de procesamiento cuando está disponible; si no, `null`. Puede ser null. | | `destination.identification` | object | sí | Identificación de la parte (clave de catálogo `type` + `number`). Objeto solo cuando al menos un campo se conoce; si no, `null`. No expone los códigos internos de tipo de SINPE (`0`–`9`); los tipos sin equivalencia se omiten (`type: null`). `number` es el valor público enviado por el comercio (dígitos, sin guiones SINPE). Los pagos históricos aún pueden devolver la forma de visualización SINPE con guiones. Puede ser null. | | `destination.identification.type` | string | no | Clave del catálogo de identificación (ej. `cedula`, `juridica`). `null` cuando se desconoce. Puede ser null. | | `destination.identification.number` | string | no | Número de identificación público. Los pagos PIN nuevos devuelven el valor enviado por el comercio (dígitos, sin guiones SINPE). Los pagos históricos aún pueden devolver la forma de visualización SINPE (con guiones, posiblemente con relleno). Puede ser null. | | `client_reference` | string | no | Referencia del comercio enviada al crear el pago (estable después del procesamiento). Mismo campo que `payment.client_reference` del webhook. | | `external_reference` | string | no | Rail/SINPE transaction id. Same field, location, and meaning as webhook `payment.external_reference` on `payment.succeeded` / `payment.failed` Sibling of `client_reference`. `null` if none. Puede ser null. | | `provider` | object | no | Foto compartida del proveedor en las lecturas REST de pagos y en los sobres de webhook. La referencia del riel solo está en `payment.external_reference`, no se duplica aquí. Los `provider_status_*` coinciden con `rejection.reason_code` / `message` / `code` del webhook cuando el proveedor rechazó la operación. `null` cuando no hay rechazo. | | `provider.correlation_id` | string | sí | Provider transaction correlation identifier. Sent to SINPE as the correlation id. Not `channel_reference` (e.g. `MOBILE_APP`). Distinct from webhook `event.correlation_id` (HTTP request id for this delivery). `null` when unknown. Puede ser null. | | `provider.occurred_at` | string (date-time) | sí | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `provider.provider_status_code` | string | sí | Motivo/código crudo del proveedor (ej. `31`). Mismo significado que `rejection.reason_code` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `provider.provider_status_desc` | string | sí | Texto Motivo del proveedor (prefiere Detalle). Mismo significado que `rejection.message` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `provider.provider_status_semantic` | string | sí | Semántica normalizada de la plataforma (ej. `ACCOUNT_BLOCKED`). Mismo significado que `rejection.code` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `error` | object | no | Siempre presente. `null` cuando no hay información de fallo (`succeeded`, `pending`, o failed/reversed sin taxonomía). El objeto usa la misma forma `domain` / `platform` que el webhook `payment.failed`. Puede ser null. | | `error.domain` | string | sí | Mismo catálogo que `payment.error.domain` del webhook. Values: provider_rejection, platform_validation, platform_posting, platform_infra, platform_reversal | | `error.platform` | object | sí | — | | `error.platform.code` | string | sí | Código público estable de la plataforma (igual que `payment.error.platform.code` del webhook). | | `error.platform.message` | string | sí | Mensaje accionable (prefiere el Detalle del proveedor). Igual que `payment.error.platform.message` del webhook. | **Ejemplo de respuesta** ```json { "success": true, "http_status_code": 200, "response_code": "OK", "message": "The request was processed successfully.", "correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "data": { "schema_version": "1.0.0", "payment_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d", "public_id": "10234", "type": "PAYOUT", "payment_method_code": "PIN", "status": "posted", "status_detail": "POSTED", "result": "succeeded", "succeeded_at": "2026-01-15T12:00:00Z", "has_reversal": false, "reversed_at": null, "created_at": "2026-01-15T12:00:00Z", "updated_at": "2026-01-15T12:00:00Z", "amount": { "amount": "1000.00", "currency": "CRC", "fees": "0.00", "taxes": "0.00" }, "source": { "account": { "type": "IBAN", "value": "CR26036900101010588061", "currency": "CRC" }, "name": "María González", "identification": { "type": "cedula", "number": "0205620043" } }, "destination": { "account": { "type": "IBAN", "value": "CR16010400000000000031", "currency": "CRC" }, "name": "Juan Perez", "identification": { "type": "cedula", "number": "0101010101" } }, "client_reference": "INV-1001", "external_reference": "SINPE-20260115-000123", "provider": { "correlation_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "occurred_at": "2026-01-15T12:00:00Z", "provider_status_code": "00", "provider_status_desc": "Aprobada", "provider_status_semantic": "SUCCESS" }, "error": null } } ``` **Respuestas de error** | HTTP | response_code | Descripción | |---|---|---| | 400 | `INVALID_REQUEST` | Invalid request. Check the required fields and try again. | | 401 | `UNAUTHORIZED` | Unauthorized. Verify your session or credentials. | | 403 | `FORBIDDEN` | You do not have permission to perform this action. | | 403 | `ACCOUNT_ACCESS_DENIED` | The actor does not have access to the requested account. | | 404 | `PAYMENT_NOT_FOUND` | Payment not found. | | 500 | `INTERNAL_ERROR` | An unexpected error occurred. Please try again later. | | 502 | `PROVIDER_ERROR` | Unable to complete the request with the payment provider. Please try again later. | | 503 | `SERVICE_UNAVAILABLE` | A required service is temporarily unavailable. Please try again later. | ### Obtener pago por id [#get-transactions-payments-payment-id] ```http GET /api/public/v1/transactions/payments/{payment_id} ``` Host: `https://api-baas-sandbox.tilopay.com` — requiere `Authorization: Bearer `. Devuelve un solo pago con el mismo contrato público del listado, incluidos el `result` consolidado, `succeeded_at`, `has_reversal` y `error`. `error` es `null` cuando no hay información de fallo; es un objeto solo cuando `domain` / `platform` está presente (`result` es `failed` o `reversed`), misma forma que `payment.error` del webhook `payment.failed`. `source` / `destination` usan `null` para campos anidados desconocidos y nunca exponen UUID internos de cuenta. `identification.number` en pagos PIN es el número público enviado por el comercio (dígitos, sin guiones SINPE). Los pagos antiguos aún pueden devolver la forma SINPE con guiones. Usalo como respaldo de los webhooks. Busca un pago por cualquiera de estos identificadores: - `payment_id` (UUID interno) - `public_id` (identificador público numérico) Para `client_reference`, usá `POST /api/public/v1/transactions/payments/search`. **Parámetros** | Parámetro | En | Tipo | Obligatorio | Descripción | |---|---|---|---|---| | `X-Correlation-Id` | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta. Se devuelve como `correlation_id` en el sobre de respuesta. Si lo omitís, la API genera uno y igual lo devuelve. | | `payment_id` | path | string | sí | UUID interno del pago o public_id numérico. | **200** — La solicitud se procesó correctamente. Campos de `data`: | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `schema_version` | string | sí | Versión del contrato de lectura de pagos. Mismo valor que el `schema_version` del sobre del webhook (`1.0.0`) para `payment.succeeded` / `payment.failed`. | | `payment_id` | string (uuid) | sí | UUID del pago devuelto al crearlo. Llave del pago para el comercio en `GET /transactions/payments/{payment_id}` y en la búsqueda. No es un id interno de cuenta. | | `public_id` | string | no | Identificador público numérico del pago devuelto al crearlo. `null` si aún no se asigna. No es un UUID interno de cuenta. Es el mismo identificador: número en webhooks y texto en REST. Tratalo siempre como texto. Puede ser null. | | `type` | string | sí | Tipo de pago derivado de la dirección (`PAYIN` / `PAYOUT`). | | `payment_method_code` | string | sí | Catálogo público de métodos de pago (`PIN`, `SINPE_MOVIL`). Mismos valores que en los webhooks. Values: PIN, SINPE_MOVIL | | `status` | string | sí | Catálogo público de estados del pago. Siempre en minúsculas. Mismos valores en REST (crear, listar, obtener) y en webhooks (`payment.status`). Los estados internos del ciclo de vida se consolidan: - `pending`: iniciado, validado, aceptado - `processing`: procesando, pendiente de procesamiento, registrando - `confirmed`: confirmado por el riel, aún no registrado en el ledger - `posted`: registrado en el ledger (se mantiene `posted` tras un reverso posterior) - `failed`: fallido, rechazado, posting_failed, cancelado, expirado Un reverso **no** es un estado. Usá `result=reversed` / `has_reversal=true` en REST y el webhook `payment.reversed`. El detalle operativo queda en `status_detail` (nombre interno en mayúsculas) en crear/listar/obtener de REST. El webhook `payment.failed` usa `error.platform.code` para distinguir fallos de registro de rechazos del proveedor. Values: pending, processing, confirmed, posted, failed | | `status_detail` | string | no | Estado operativo (interno) en mayúsculas, ej. `VALIDATED`, `POSTED`, `POSTING_FAILED`. Complemento del catálogo público `status`. Independiente de `result` (`posted` es el hito de débito/registro, no el éxito del proveedor). | | `result` | string | sí | Resultado de negocio consolidado para conciliación (respaldo de los webhooks). Independiente del `status` de procesamiento. Se deriva así: `reversed` cuando `has_reversal` es true (prioridad más alta); `succeeded` cuando `succeeded_at` está presente y no hay reverso; `failed` cuando el estado de procesamiento es `failed` o `posting_failed`; si no, `pending`. Un pago registrado (posted) que luego se revirtió tiene `status=posted` y `result=reversed`. Values: succeeded, failed, reversed, pending | | `succeeded_at` | string (date-time) | no | Marca de tiempo de confirmación de éxito del proveedor (RFC 3339 UTC, precisión de segundos, `Z`). Null mientras el pago ya pueda estar `posted` internamente pero el proveedor no haya confirmado el éxito. Puede ser null. | | `has_reversal` | boolean | sí | True cuando se aplicó un reverso. Independiente de `status`. Se correlaciona con el webhook `payment.reversed`. | | `reversed_at` | string (date-time) | no | Cuándo se aplicó el reverso. Null cuando `has_reversal` es false. Puede ser null. | | `created_at` | string (date-time) | no | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `updated_at` | string (date-time) | no | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `amount` | object | no | Misma forma monetaria que la creación de pago (`PaymentAmount`). | | `amount.amount` | string | sí | — | | `amount.currency` | string | sí | — | | `source` | object | no | Parte del pago en las lecturas del API. Los campos anidados siempre están presentes: `null` cuando el valor se desconoce. `account` es un identificador público (`IBAN` o `PHONE`); nunca se devuelven UUID internos de cuenta. | | `source.account` | object | sí | Identificador público de la cuenta (`type` + `value`). `null` cuando el IBAN o el teléfono no pueden resolverse. Nunca un UUID interno de cuenta. Puede ser null. | | `source.account.type` | string | sí | **Esquema de identificación** de la cuenta (ej. `IBAN`, `PHONE`). No es la clasificación interna de la cuenta (ej. operativa). Values: IBAN, PHONE | | `source.account.value` | string | sí | Cuando `type` es `PHONE` (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777"). | | `source.account.currency` | string | no | Moneda opcional de la cuenta en las respuestas. | | `source.name` | string | sí | Nombre de la parte según los datos de procesamiento cuando está disponible; si no, `null`. Puede ser null. | | `source.identification` | object | sí | Identificación de la parte (clave de catálogo `type` + `number`). Objeto solo cuando al menos un campo se conoce; si no, `null`. No expone los códigos internos de tipo de SINPE (`0`–`9`); los tipos sin equivalencia se omiten (`type: null`). `number` es el valor público enviado por el comercio (dígitos, sin guiones SINPE). Los pagos históricos aún pueden devolver la forma de visualización SINPE con guiones. Puede ser null. | | `source.identification.type` | string | no | Clave del catálogo de identificación (ej. `cedula`, `juridica`). `null` cuando se desconoce. Puede ser null. | | `source.identification.number` | string | no | Número de identificación público. Los pagos PIN nuevos devuelven el valor enviado por el comercio (dígitos, sin guiones SINPE). Los pagos históricos aún pueden devolver la forma de visualización SINPE (con guiones, posiblemente con relleno). Puede ser null. | | `destination` | object | no | Parte del pago en las lecturas del API. Los campos anidados siempre están presentes: `null` cuando el valor se desconoce. `account` es un identificador público (`IBAN` o `PHONE`); nunca se devuelven UUID internos de cuenta. | | `destination.account` | object | sí | Identificador público de la cuenta (`type` + `value`). `null` cuando el IBAN o el teléfono no pueden resolverse. Nunca un UUID interno de cuenta. Puede ser null. | | `destination.account.type` | string | sí | **Esquema de identificación** de la cuenta (ej. `IBAN`, `PHONE`). No es la clasificación interna de la cuenta (ej. operativa). Values: IBAN, PHONE | | `destination.account.value` | string | sí | Cuando `type` es `PHONE` (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777"). | | `destination.account.currency` | string | no | Moneda opcional de la cuenta en las respuestas. | | `destination.name` | string | sí | Nombre de la parte según los datos de procesamiento cuando está disponible; si no, `null`. Puede ser null. | | `destination.identification` | object | sí | Identificación de la parte (clave de catálogo `type` + `number`). Objeto solo cuando al menos un campo se conoce; si no, `null`. No expone los códigos internos de tipo de SINPE (`0`–`9`); los tipos sin equivalencia se omiten (`type: null`). `number` es el valor público enviado por el comercio (dígitos, sin guiones SINPE). Los pagos históricos aún pueden devolver la forma de visualización SINPE con guiones. Puede ser null. | | `destination.identification.type` | string | no | Clave del catálogo de identificación (ej. `cedula`, `juridica`). `null` cuando se desconoce. Puede ser null. | | `destination.identification.number` | string | no | Número de identificación público. Los pagos PIN nuevos devuelven el valor enviado por el comercio (dígitos, sin guiones SINPE). Los pagos históricos aún pueden devolver la forma de visualización SINPE (con guiones, posiblemente con relleno). Puede ser null. | | `client_reference` | string | no | Referencia del comercio enviada al crear el pago (estable después del procesamiento). Mismo campo que `payment.client_reference` del webhook. | | `external_reference` | string | no | Rail/SINPE transaction id. Same field, location, and meaning as webhook `payment.external_reference` on `payment.succeeded` / `payment.failed` Sibling of `client_reference`. `null` if none. Puede ser null. | | `provider` | object | no | Foto compartida del proveedor en las lecturas REST de pagos y en los sobres de webhook. La referencia del riel solo está en `payment.external_reference`, no se duplica aquí. Los `provider_status_*` coinciden con `rejection.reason_code` / `message` / `code` del webhook cuando el proveedor rechazó la operación. `null` cuando no hay rechazo. | | `provider.correlation_id` | string | sí | Provider transaction correlation identifier. Sent to SINPE as the correlation id. Not `channel_reference` (e.g. `MOBILE_APP`). Distinct from webhook `event.correlation_id` (HTTP request id for this delivery). `null` when unknown. Puede ser null. | | `provider.occurred_at` | string (date-time) | sí | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `provider.provider_status_code` | string | sí | Motivo/código crudo del proveedor (ej. `31`). Mismo significado que `rejection.reason_code` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `provider.provider_status_desc` | string | sí | Texto Motivo del proveedor (prefiere Detalle). Mismo significado que `rejection.message` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `provider.provider_status_semantic` | string | sí | Semántica normalizada de la plataforma (ej. `ACCOUNT_BLOCKED`). Mismo significado que `rejection.code` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `error` | object | no | Siempre presente. `null` cuando no hay información de fallo (`succeeded`, `pending`, o failed/reversed sin taxonomía). El objeto usa la misma forma `domain` / `platform` que el webhook `payment.failed`. Puede ser null. | | `error.domain` | string | sí | Mismo catálogo que `payment.error.domain` del webhook. Values: provider_rejection, platform_validation, platform_posting, platform_infra, platform_reversal | | `error.platform` | object | sí | — | | `error.platform.code` | string | sí | Código público estable de la plataforma (igual que `payment.error.platform.code` del webhook). | | `error.platform.message` | string | sí | Mensaje accionable (prefiere el Detalle del proveedor). Igual que `payment.error.platform.message` del webhook. | **Ejemplo de respuesta** ```json { "success": true, "http_status_code": 200, "response_code": "OK", "message": "The request was processed successfully.", "correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "data": { "schema_version": "1.0.0", "payment_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d", "public_id": "10234", "type": "PAYOUT", "payment_method_code": "PIN", "status": "posted", "status_detail": "POSTED", "result": "succeeded", "succeeded_at": "2026-01-15T12:00:00Z", "has_reversal": false, "reversed_at": null, "created_at": "2026-01-15T12:00:00Z", "updated_at": "2026-01-15T12:00:00Z", "amount": { "amount": "1000.00", "currency": "CRC", "fees": "0.00", "taxes": "0.00" }, "source": { "account": { "type": "IBAN", "value": "CR26036900101010588061", "currency": "CRC" }, "name": "María González", "identification": { "type": "cedula", "number": "0205620043" } }, "destination": { "account": { "type": "IBAN", "value": "CR16010400000000000031", "currency": "CRC" }, "name": "Juan Perez", "identification": { "type": "cedula", "number": "0101010101" } }, "client_reference": "INV-1001", "external_reference": "SINPE-20260115-000123", "provider": { "correlation_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "occurred_at": "2026-01-15T12:00:00Z", "provider_status_code": "00", "provider_status_desc": "Aprobada", "provider_status_semantic": "SUCCESS" }, "error": null } } ``` **Respuestas de error** | HTTP | response_code | Descripción | |---|---|---| | 400 | `INVALID_REQUEST` | Invalid request. Check the required fields and try again. | | 401 | `UNAUTHORIZED` | Unauthorized. Verify your session or credentials. | | 403 | `FORBIDDEN` | You do not have permission to perform this action. | | 403 | `ACCOUNT_ACCESS_DENIED` | The actor does not have access to the requested account. | | 404 | `PAYMENT_NOT_FOUND` | Payment not found. | | 500 | `INTERNAL_ERROR` | An unexpected error occurred. Please try again later. | | 502 | `PROVIDER_ERROR` | Unable to complete the request with the payment provider. Please try again later. | | 503 | `SERVICE_UNAVAILABLE` | A required service is temporarily unavailable. Please try again later. | ## Procesamiento y límites [#procesamiento] La creación de pagos en el API no tiene doble control: el pago se procesa directamente si el token, los permisos y los datos son válidos. Aplican límites por transacción, diarios y mensuales, en monto y cantidad. Si se supera alguno, el pago falla durante el procesamiento y se notifica con el evento `payment.failed`. El flujo de confirmación de transferencias del [servidor MCP](/developers/agentes/mcp/api-bancario) es independiente de esta creación directa del API. --- # Cuentas del API Bancario > Operaciones de cuentas del API Bancario: validación, listado, saldos y estados de cuenta. - kind: api-operation - status: stable - api_version: 1.0.0 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/api-bancario/cuentas El grupo `Accounts` cubre la cuenta como recurso: validar una cuenta destino antes de transferir, listar las cuentas accesibles, consultar saldos y pedir estados de cuenta. ```http POST /api/public/v1/accounts/validate GET /api/public/v1/accounts POST /api/public/v1/accounts/balances GET /api/public/v1/accounts/balance POST /api/public/v1/accounts/statements GET /api/public/v1/accounts/statements/{request_id} ``` ## Reglas del recurso [#reglas] **Alcance.** El listado devuelve sólo las cuentas que autoriza el token; no se envía `tenant_id` ni `owner_id` como parámetro. **Validación previa.** Validá la cuenta destino antes de crear un pago: la operación confirma que la cuenta existe y es apta, y devuelve los datos del titular que el servicio expone. **Estados de cuenta asincrónicos.** `POST /api/public/v1/accounts/statements` acepta `Idempotency-Key` y responde siempre **HTTP 202 (`ACCEPTED`)** con `request_id` y `status: PENDING`; la generación es asíncrona. Consultá `GET /api/public/v1/accounts/statements/{request_id}`: responde **HTTP 200** con `status` `PENDING`, `PROCESSING`, `DONE` o `ERROR`. En `DONE` incluye `download_url`, **válida por 48 horas**. Ver [reintentos seguros](/developers/api-bancario/convenciones#reintentos). **Paginación.** `GET /api/public/v1/accounts` y `GET /api/public/v1/accounts/balances` usan `limit` y `offset`, y devuelven `pagination` con `limit`, `offset` y `total`. ## Operaciones [#operaciones] ### Validar cuenta externa para un método de pago [#post-accounts-validate] ```http POST /api/public/v1/accounts/validate ``` Host: `https://api-baas-sandbox.tilopay.com` — requiere `Authorization: Bearer `. Valida una cuenta de beneficiario (IBAN o teléfono) a través del proveedor SINPE para el método de pago indicado. No valida cuentas internas de la plataforma. Cuando es válida, `data.holder.id_type` usa las mismas claves del catálogo de identificación que `identification.type` en `POST /payments` (ej. `cedula`, `juridica`, `dimex`). ## Disponibilidad de campos en SINPE_MOVIL (esperado, estable) Para `payment_method_code = SINPE_MOVIL`, la consulta del monedero SINPE Móvil no devuelve el tipo de identificación ni el nombre de la entidad. Una validación exitosa **puede** entonces devolver: - `data.holder.id_type` = `unknown` - `data.financial_institution.entity_name` = `""` (cadena vacía) Este comportamiento es **esperado y estable**, no un error de mapeo ni un error transitorio del proveedor. PIN (la consulta de la cuenta en SINPE) sí completa ambos campos. No reportés estos valores como defectos ni asumás que `holder.id_type` o `financial_institution.entity_name` siempre vienen completos cuando `is_valid` es true. ## Códigos de rechazo SINPE (`data.rejection`) Cuando `is_valid` es `false`, `data.rejection` explica por qué (ver el ejemplo `rejected` en la respuesta `200` más abajo). `rejection.code` es uno de un conjunto fijo de semánticas normalizadas (ver la tabla de valores más abajo). **La mayoría de filas de la tabla NO tienen un `code` propio**: solo un subconjunto de valores de `reason_code` tiene una semántica dedicada; cualquier otro `reason_code`, incluso uno listado abajo con un `message` específico, devuelve `code = SINPE_REJECTED` (ej. `reason_code = 21` "fondos insuficientes" igual devuelve `SINPE_REJECTED`). Este mismo objeto y catálogo los usa también el campo `rejection` del webhook `payment.failed`. Un `reason_code` que no aparece aquí igual produce respuesta: `message` cae a un texto genérico y `code` a `SINPE_REJECTED`. **Cuenta / perfil / límites** | Code | Message | |---|---| | 21 | Cuenta Cliente con fondos insuficientes | | 22 | Cuenta Cliente no admite créditos | | 23 | Cuenta Cliente cerrada | | 24 | Cuenta Cliente inactiva | | 25 | Cuenta Cliente no admite débitos | | 26 | Cuenta Cliente no es de fondos | | 27 | Moneda de la Cuenta Cliente no corresponde | | 28 | Cuenta cliente no existe | | 29 | Cuenta Cliente no registrada en el SINPE | | 30 | Cuenta Cliente no habilitada para el servicio | | 31 | Cuenta Cliente bloqueada | | 32 | Id cliente destino no coincide con registrado en la entidad | | 33 | Nombre del cliente destino no coincide con el registrado en la entidad | | 34 | Cuenta Cliente en proceso de cierre | | 35 | Cuenta Cliente embargada | | 36 | Cuenta Cliente con retención judicial | | 37 | Cuenta de expediente simplificado no permite el monto indicado | | 38 | Límite transaccional de la Cuenta Cliente excedido | | 39 | Cuenta Cliente incorrecta | | 40 | IBAN de la cuenta destino inválido | | 41 | IBAN de la cuenta origen inválido | | 42 | Tipo de cuenta no permite la transacción | | 43 | Cuenta Cliente no pertenece a la entidad indicada | | 44 | Producto de la cuenta no admite el servicio | | 45 | Cuenta Cliente en estado de cancelación | | 46 | Cuenta Cliente restringida por política de la entidad | | 47 | Cuenta Cliente no permite pagos inmediatos | | 48 | Cuenta Cliente no permite SINPE Móvil | | 49 | Titular de la cuenta destino fallecido | | 50 | Cuenta Cliente consolidada o migrada | | 51 | Identificación del cliente origen no coincide | | 52 | Identificación del cliente destino inválida | | 53 | Cliente destino no autorizado para recibir el pago | | 54 | Cliente origen no autorizado para enviar el pago | | 55 | Perfil del cliente origen no permite la transacción | | 56 | Monto inferior al mínimo permitido | | 57 | Monto superior al máximo permitido | | 58 | Cantidad de transacciones diarias excedida | | 59 | Cantidad de transacciones mensuales excedida | | 60 | Límite acumulado diario excedido | | 61 | Límite acumulado mensual excedido | | 62 | Comisión no pudo ser aplicada | | 63 | Tipo de cambio no disponible | | 64 | Transacción rechazada por control de lavado de dinero | | 65 | Transacción rechazada por listas de control | | 66 | Transacción en revisión de cumplimiento | | 67 | Documento de respaldo requerido no presente | | 68 | Firma o autenticación inválida | | 69 | Token o segundo factor inválido | | 70 | Sesión de usuario expirada | | 71 | Usuario no autorizado para el canal | | 72 | Dispositivo no registrado | | 73 | Geolocalización no permitida | | 74 | Operación no soportada en la moneda indicada | | 75 | Operación no soportada para el tipo de cliente | | 76 | Problemas de comunicación | | 77 | Tiempo de espera agotado en la entidad origen | | 78 | Tiempo de espera agotado en el SINPE | | 79 | Error interno de la entidad origen | | 80 | Error interno de la entidad destino | | 81 | Entidad origen no disponible | | 82 | Entidad destino no encontrada | | 83 | Problemas en la respuesta del destino | | 84 | Respuesta de la entidad origen incorrecta | | 85 | Mensaje con formato electrónico inválido | | 86 | Versión del estándar electrónico no soportada | | 87 | Campo obligatorio no informado | | 88 | Campo con valor fuera de catálogo | | 89 | Checksum o integridad del mensaje inválida | | 90 | Referencia SINPE duplicada | | 91 | Moneda no corresponde | | 92 | Transacción no autorizada por entidad destino | | 93 | Transacción no autorizada por cliente destino | | 94 | Transacción no autorizada por entidad origen | | 95 | Transacción no autorizada por cliente origen | | 96 | Reverso no permitido para el estado de la transacción | | 97 | Reverso ya aplicado | | 98 | Confirmación no permitida para el estado de la transacción | | 99 | Liquidación no permitida para el estado de la transacción | | 100 | Entidad Destino no disponible para procesar en tiempo real | | 101 | Entidad origen no disponible para procesar en tiempo real | | 102 | Servicio PIN no habilitado para la entidad destino | | 103 | Servicio PIN no habilitado para la entidad origen | | 104 | Código de entidad destino inválido | | 105 | Código de entidad origen inválido | | 106 | Código de país de la entidad destino inválido | | 107 | Código de país de la entidad origen inválido | | 108 | Número de referencia interna inválido | | 109 | Número de referencia SINPE inválido | | 110 | Transacción no se encuentra en un estado que permita la consulta | **Compensación con entidad destino** | Code | Message | |---|---| | 201 | Tiempo respuesta excedido por la entidad destino | | 202 | Respuesta de la entidad destino incorrecta según el estándar electrónico | | 203 | Se recibió una excepción de la entidad destino | | 204 | Error de comunicación con la entidad destino | | 205 | Falló procesamiento en el SINPE | | 206 | Transacción no autorizada por cliente destino | | 207 | Perfil transaccional del cliente destino no permite recibir el pago | | 208 | Operación no autorizada entre las entidades participantes | | 209 | Pendientes de Cumplimiento | | 210 | Conciliación de la transacción no fue posible | **Identificación** | Code | Message | |---|---| | 801 | Identificación inválida | | 802 | Identificación del cliente origen no encontrada | | 803 | Identificación del cliente destino no encontrada | | 804 | Identificación no vigente | | 805 | Identificación vencida | | 806 | Identificación no corresponde al tipo indicado | | 807 | Tipo de identificación inválido | | 808 | País de la identificación no soportado | | 809 | Identificación de menor de edad no permitida | | 810 | Identificación de persona jurídica no permitida para el servicio | **Validación de formato / Core Bancario** | Code | Message | |---|---| | 1002 | El Id de cliente destino no cumple con el formato esperado por el SINPE | | 1003 | El Id de cliente origen no fue informado | | 1004 | El Id de cliente origen no cumple con el formato esperado por el SINPE | | 1005 | Monto con formato inválido | | 1006 | Moneda con formato inválido | | 1007 | Problemas de comunicación con el Core Bancario | | 1008 | Core Bancario no disponible | | 1009 | El valor para el campo no puede ser nulo o infringir su longitud mínima o máxima | | 1010 | El valor para el campo no corresponde al tipo de dato esperado | | 1011 | El valor para el campo no corresponde al catálogo permitido | | 1012 | Fecha con formato inválido | | 1013 | Hora con formato inválido | | 1014 | Número de referencia con formato inválido | | 1015 | IBAN con formato inválido | **Canal / tipo de identificación** | Code | Message | |---|---| | 1040 | Canal no informado | | 1041 | Canal inválido | | 1042 | Canal no corresponde | | 1043 | Canal no habilitado para la entidad | | 1044 | Canal no habilitado para el servicio | | 1045 | El formato de la identificación es inválido | | 1046 | Tipo de identificación no informado | | 1080 | Tipo de identificación no corresponde al cliente origen | | 1081 | Tipo de identificación no corresponde al cliente destino | | 1082 | Tipo de identificación no vigente | | 1083 | Tipo de identificación no soportado por el servicio | | 1084 | Tipo de identificación inválido | | 1085 | Tipo de identificación no soportado por la entidad | **SINPE Móvil (monedero)** | Code | Message | |---|---| | 15300 | El número de teléfono origen indicado es inválido | | 15301 | El número de teléfono origen no tiene activo el Servicio Monedero | | 15302 | El número de teléfono destino indicado es inválido | | 15303 | El número de teléfono destino no está registrado en el padrón móvil del BCCR | | 15304 | No es posible inactivar el monedero indicado pues no existe | | 15305 | El número de teléfono indicado ya se encuentra activo como monedero en el padrón local | **Valores de `rejection.code`** | Valor | Significado | |---|---| | `ACCOUNT_CLOSED` | Cuenta cerrada | | `ACCOUNT_NOT_FOUND` | Cuenta no encontrada | | `ACCOUNT_BLOCKED` | Cuenta bloqueada | | `INVALID_ACCOUNT` | Cuenta inválida | | `IDENT_MISMATCH` | La identificación no coincide | | `IDENT_TYPE_INVALID` | Tipo de identificación inválido | | `INVALID_ID_FORMAT` | Formato de identificación inválido | | `VALIDATION_ERROR` | Error de validación | | `CURRENCY_MISMATCH` | La moneda no corresponde | | `NOT_AUTHORIZED_BY_RECIPIENT` | No autorizado por el destinatario | | `PROFILE_NOT_ALLOWED` | Perfil no permitido | | `CHANNEL_NOT_RECOGNIZED` | Canal no reconocido | | `COMMUNICATION_ERROR` | Error de comunicación | | `RETRY_LATER` | Reintentar más tarde | | `WALLET_PHONE_ORIGIN_INVALID` | Teléfono origen inválido (SINPE Móvil) | | `WALLET_PHONE_ORIGIN_NOT_ENABLED` | Teléfono origen sin servicio de monedero | | `WALLET_PHONE_DEST_INVALID` | Teléfono destino inválido (SINPE Móvil) | | `WALLET_PHONE_NOT_REGISTERED_BCCR` | Teléfono no registrado en el padrón móvil del BCCR | | `WALLET_NOT_FOUND` | Monedero no encontrado | | `WALLET_PHONE_ALREADY_ACTIVE` | El teléfono ya tiene un monedero activo | | `PHONE_NOT_REGISTERED` | Teléfono no registrado | | `SINPE_REJECTED` | Rechazado por SINPE (valor genérico de respaldo) | Actualmente hay límites de tasa en autenticación y validación de cuentas. Superarlos devuelve HTTP 429 (TOO_MANY_REQUESTS). Reintentá con espera exponencial. El código SINPE 1001 indica que la cuenta existe y está activa; es un resultado válido, no un motivo de rechazo. **Parámetros** | Parámetro | En | Tipo | Obligatorio | Descripción | |---|---|---|---|---| | `X-Correlation-Id` | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta. Se devuelve como `correlation_id` en el sobre de respuesta. Si lo omitís, la API genera uno y igual lo devuelve. | **Cuerpo del request** | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `payment_method_code` | string | sí | Método de pago usado para enrutar la validación (PIN para IBAN externo, SINPE_MOVIL para monedero telefónico). Values: PIN, SINPE_MOVIL | | `account` | object | sí | — | | `account.type` | string | sí | Values: IBAN, PHONE | | `account.value` | string | sí | — | **Ejemplo de request** — pin ```json { "payment_method_code": "PIN", "account": { "type": "IBAN", "value": "CR16010400000000000031" } } ``` **Ejemplo de request** — sinpe_movil ```json { "payment_method_code": "SINPE_MOVIL", "account": { "type": "PHONE", "value": "88887777" } } ``` **200** — La solicitud se procesó correctamente. Campos de `data`: | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `is_valid` | boolean | no | — | | `account` | object | no | — | | `account.type` | string | no | — | | `account.value` | string | no | — | | `account.currency` | string | no | — | | `account.product_name` | string | no | — | | `holder` | object | no | Titular de la cuenta cuando la validación tiene éxito. `id_type` coincide con `PaymentIdentification.type` (mismo catálogo que POST /payments). Para SINPE_MOVIL, `id_type` puede ser `unknown` porque la consulta del monedero no devuelve el tipo de identificación. Es esperado y estable; no lo tratés como un error. Puede ser null. | | `holder.name` | string | no | — | | `holder.id_type` | string | no | Clave del catálogo de identificación (minúsculas), ej. `cedula`, `juridica`, `dimex`. Mismo vocabulario que `identification.type` al crear un pago. PIN: se obtiene de la consulta de cuenta del proveedor (confirmado por el proveedor). SINPE_MOVIL: la consulta del monedero no devuelve el tipo de identificación, así que este campo **puede ser `unknown`**. Es un comportamiento esperado y estable por los datos disponibles del proveedor, no un error de mapeo ni transitorio. No asumás que siempre hay un tipo confirmado. Values: cedula, dimex, gobierno, juridica, institucion_autonoma, didi, pasaporte, unknown | | `holder.id_number` | string | no | — | | `financial_institution` | object | no | Entidad del beneficiario cuando la validación tiene éxito. PIN completa `entity_name` desde la consulta de cuenta en SINPE. SINPE_MOVIL solo recibe el **código** de entidad desde la consulta del monedero; no devuelve el nombre de la entidad, así que `entity_name` **puede ser `""`**. Es un comportamiento esperado y estable, no un error transitorio. No asumás que `entity_name` siempre viene completo. Puede ser null. | | `financial_institution.country_code` | string | no | — | | `financial_institution.entity_code` | string | no | — | | `financial_institution.entity_name` | string | no | Nombre legible de la entidad. PIN: se completa desde la consulta de cuenta del proveedor. SINPE_MOVIL: puede ser `""` porque la consulta del monedero no expone el nombre. Limitación esperada, no un error. | | `rejection` | object | no | Presente cuando `is_valid` es `false` y el proveedor rechazó la cuenta. `null` cuando `is_valid` es `true`. Puede ser null. | | `rejection.code` | string | sí | Semántica normalizada de la plataforma derivada de `reason_code`. Solo un subconjunto de valores de `reason_code` (ver el catálogo en la descripción de `POST /accounts/validate` y del endpoint de contrato del webhook `payment.failed`) tiene entrada propia aquí; para cualquier otro `reason_code` numérico, `code` es `SINPE_REJECTED` aunque `message` sea específico (ej. `reason_code = 21` "fondos insuficientes" igual devuelve `code = SINPE_REJECTED`, no tiene semántica propia). `PHONE_NOT_REGISTERED` es el valor de respaldo cuando `reason_code` no es numérico (flujo del monedero SINPE_MOVIL). Values: ACCOUNT_CLOSED, ACCOUNT_NOT_FOUND, ACCOUNT_BLOCKED, INVALID_ACCOUNT, IDENT_MISMATCH, IDENT_TYPE_INVALID, INVALID_ID_FORMAT, VALIDATION_ERROR, CURRENCY_MISMATCH, NOT_AUTHORIZED_BY_RECIPIENT, PROFILE_NOT_ALLOWED, CHANNEL_NOT_RECOGNIZED, COMMUNICATION_ERROR, RETRY_LATER, WALLET_PHONE_ORIGIN_INVALID, WALLET_PHONE_ORIGIN_NOT_ENABLED, WALLET_PHONE_DEST_INVALID, WALLET_PHONE_NOT_REGISTERED_BCCR, WALLET_NOT_FOUND, WALLET_PHONE_ALREADY_ACTIVE, PHONE_NOT_REGISTERED, SINPE_REJECTED | | `rejection.reason_code` | string | sí | Motivo/código crudo devuelto por SINPE. El catálogo completo está en la descripción de `POST /accounts/validate` (lo comparte este objeto dondequiera que aparezca, incluido el webhook `payment.failed`). Un código no listado igual produce respuesta: `message` cae a un texto genérico y `code` a `SINPE_REJECTED`. | | `rejection.message` | string | sí | Texto descriptivo del Motivo; prefiere el `Detalle` del proveedor cuando existe. | | `provider` | object | no | — | | `provider.operation` | string | no | — | | `provider.correlation_id` | string | no | Puede ser null. | | `provider.occurred_at` | string (date-time) | no | Puede ser null. | **Ejemplo de respuesta** — valid ```json { "success": true, "http_status_code": 200, "response_code": "OK", "message": "The request was processed successfully.", "correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "data": { "is_valid": true, "account": { "type": "IBAN", "value": "CR16010400000000000031", "currency": "CRC", "product_name": "Cuenta corriente" }, "holder": { "name": "Juan Perez", "id_type": "cedula" }, "financial_institution": { "entity_code": "104", "entity_name": "Banco Ejemplo" }, "provider": { "reason_code": "0", "message": "Cuenta válida", "code": null }, "rejection": null } } ``` **Ejemplo de respuesta** — rejected ```json { "success": true, "http_status_code": 200, "response_code": "OK", "message": "The request was processed successfully.", "correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "data": { "is_valid": false, "account": { "type": "IBAN", "value": "CR16010400000000000099", "currency": "CRC", "product_name": "" }, "holder": null, "financial_institution": { "entity_code": "104", "entity_name": "Banco Ejemplo" }, "provider": { "reason_code": "28", "message": "Cuenta cliente no existe", "code": "ACCOUNT_NOT_FOUND" }, "rejection": { "code": "ACCOUNT_NOT_FOUND", "reason_code": "28", "message": "Cuenta cliente no existe" } } } ``` **Respuestas de error** | HTTP | response_code | Descripción | |---|---|---| | 400 | `INVALID_REQUEST` | Invalid request. Check the required fields and try again. | | 400 | `INVALID_ACCOUNT_TYPE` | Unsupported or invalid account type. | | 400 | `INVALID_ACCOUNT_FORMAT` | Invalid account format. | | 400 | `INVALID_PAYMENT_METHOD` | Invalid or unsupported payment method. | | 401 | `UNAUTHORIZED` | Unauthorized. Verify your session or credentials. | | 403 | `FORBIDDEN` | You do not have permission to perform this action. | | 403 | `ACCOUNT_ACCESS_DENIED` | The actor does not have access to the requested account. | | 422 | `UNPROCESSABLE_ENTITY` | The request is well-formed but cannot be processed due to business rules. | | 429 | `TOO_MANY_REQUESTS` | Too many requests. Please retry after a short delay. | | 500 | `INTERNAL_ERROR` | An unexpected error occurred. Please try again later. | | 502 | `PROVIDER_ERROR` | Unable to complete the request with the payment provider. Please try again later. | ### Listar saldos de las cuentas accesibles [#get-accounts-balances] ```http GET /api/public/v1/accounts/balances ``` Host: `https://api-baas-sandbox.tilopay.com` — requiere `Authorization: Bearer `. Devuelve los saldos paginados de las cuentas (`account`, `amounts`, `as_of`). Este endpoint consulta el saldo actual en tiempo real y puede responder más lento que `GET /accounts`. Para los atributos de la cuenta sin montos, usá `GET /accounts`. Los filtros opcionales usan el estándar público de identificación de cuentas: `type` + `value` (esquema de identificación + valor). `type` no es la clasificación interna de la cuenta. **Parámetros** | Parámetro | En | Tipo | Obligatorio | Descripción | |---|---|---|---|---| | `X-Correlation-Id` | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta. Se devuelve como `correlation_id` en el sobre de respuesta. Si lo omitís, la API genera uno y igual lo devuelve. | | `limit` | query | integer | no | — | | `offset` | query | integer | no | — | | `type` | query | string | no | Filtro opcional por **esquema de identificación** de la cuenta (ej. `IBAN`). No es la clasificación interna de la cuenta. | | `value` | query | string | no | Filtro opcional por valor del identificador de la cuenta (los listados admiten coincidencia parcial). | **200** — La solicitud se procesó correctamente. Campos de `data`: | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `items` | array | no | — | | `items[].account` | object | sí | — | | `items[].account.type` | string | sí | **Esquema de identificación** de la cuenta (ej. `IBAN`, `PHONE`). No es la clasificación interna de la cuenta (ej. operativa). Values: IBAN, PHONE | | `items[].account.value` | string | sí | Cuando `type` es `PHONE` (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777"). | | `items[].account.currency` | string | no | Moneda opcional de la cuenta en las respuestas. | | `items[].amounts` | object | sí | Saldos del ledger como textos decimales con 2 decimales (misma escala que los montos públicos de pago). Preferí texto sobre número JSON para montos financieros. | | `items[].amounts.available` | string | no | — | | `items[].amounts.posted` | string | no | — | | `items[].amounts.inbound_in_transit` | string | no | — | | `items[].amounts.outbound_in_transit` | string | no | — | | `items[].as_of` | string (date-time) | sí | Marca de tiempo del ledger cuando se conoce (RFC 3339 UTC, precisión de segundos, `Z`); `null` cuando no está disponible. Puede ser null. | | `pagination` | object | no | — | | `pagination.limit` | integer | no | — | | `pagination.offset` | integer | no | — | | `pagination.total` | integer | no | — | **Ejemplo de respuesta** ```json { "success": true, "http_status_code": 200, "response_code": "OK", "message": "The request was processed successfully.", "correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "data": { "items": [ { "account": { "type": "IBAN", "value": "CR26036900101010588061", "currency": "CRC" }, "amounts": { "available": "991900.00", "posted": "991900.00", "inbound_in_transit": "0.00", "outbound_in_transit": "0.00" }, "as_of": "2026-01-15T12:00:00Z" } ], "pagination": { "limit": 20, "offset": 0, "total": 1 } } } ``` **Respuestas de error** | HTTP | response_code | Descripción | |---|---|---| | 400 | `INVALID_REQUEST` | Invalid request. Check the required fields and try again. | | 401 | `UNAUTHORIZED` | Unauthorized. Verify your session or credentials. | | 403 | `FORBIDDEN` | You do not have permission to perform this action. | | 403 | `ACCOUNT_ACCESS_DENIED` | The actor does not have access to the requested account. | | 404 | `NOT_FOUND` | The requested resource was not found. | | 500 | `INTERNAL_ERROR` | An unexpected error occurred. Please try again later. | | 502 | — | Error de dependencia | | 503 | `SERVICE_UNAVAILABLE` | A required service is temporarily unavailable. Please try again later. | ### Listar cuentas accesibles sin saldos [#get-accounts] ```http GET /api/public/v1/accounts ``` Host: `https://api-baas-sandbox.tilopay.com` — requiere `Authorization: Bearer `. Devuelve las cuentas accesibles paginadas sin consultar saldos actuales. Cada ítem trae solo atributos de la cuenta (`account.type`, `account.value`, `account.currency`). No incluye `amounts` ni `as_of`; usá `GET /accounts/balances` o `POST /accounts/balance`. Los filtros opcionales usan el estándar público de identificación de cuentas: `type` + `value` (esquema de identificación + valor). `type` no es la clasificación interna de la cuenta. **Parámetros** | Parámetro | En | Tipo | Obligatorio | Descripción | |---|---|---|---|---| | `X-Correlation-Id` | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta. Se devuelve como `correlation_id` en el sobre de respuesta. Si lo omitís, la API genera uno y igual lo devuelve. | | `limit` | query | integer | no | — | | `offset` | query | integer | no | — | | `type` | query | string | no | Filtro opcional por **esquema de identificación** de la cuenta (ej. `IBAN`). No es la clasificación interna de la cuenta. | | `value` | query | string | no | Filtro opcional por valor del identificador de la cuenta (los listados admiten coincidencia parcial). | **200** — La solicitud se procesó correctamente. Campos de `data`: | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `items` | array | no | — | | `items[].account` | object | sí | — | | `items[].account.type` | string | sí | **Esquema de identificación** de la cuenta (ej. `IBAN`, `PHONE`). No es la clasificación interna de la cuenta (ej. operativa). Values: IBAN, PHONE | | `items[].account.value` | string | sí | Cuando `type` es `PHONE` (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777"). | | `items[].account.currency` | string | no | Moneda opcional de la cuenta en las respuestas. | | `pagination` | object | no | — | | `pagination.limit` | integer | no | — | | `pagination.offset` | integer | no | — | | `pagination.total` | integer | no | — | **Ejemplo de respuesta** ```json { "success": true, "http_status_code": 200, "response_code": "OK", "message": "The request was processed successfully.", "correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "data": { "items": [ { "account": { "type": "IBAN", "value": "CR26036900101010588061", "currency": "CRC" } } ], "pagination": { "limit": 20, "offset": 0, "total": 1 } } } ``` **Respuestas de error** | HTTP | response_code | Descripción | |---|---|---| | 400 | `INVALID_REQUEST` | Invalid request. Check the required fields and try again. | | 401 | `UNAUTHORIZED` | Unauthorized. Verify your session or credentials. | | 403 | `FORBIDDEN` | You do not have permission to perform this action. | | 404 | `NOT_FOUND` | The requested resource was not found. | | 500 | `INTERNAL_ERROR` | An unexpected error occurred. Please try again later. | | 502 | — | Error de dependencia | | 503 | `SERVICE_UNAVAILABLE` | A required service is temporarily unavailable. Please try again later. | ### Obtener saldo de una cuenta [#post-accounts-balance] ```http POST /api/public/v1/accounts/balance ``` Host: `https://api-baas-sandbox.tilopay.com` — requiere `Authorization: Bearer `. Devuelve la foto actual de una cuenta con `amounts` y `as_of`. Para los atributos de la cuenta sin saldos, usá `GET /accounts`. **Parámetros** | Parámetro | En | Tipo | Obligatorio | Descripción | |---|---|---|---|---| | `X-Correlation-Id` | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta. Se devuelve como `correlation_id` en el sobre de respuesta. Si lo omitís, la API genera uno y igual lo devuelve. | **Cuerpo del request** | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `account` | object | sí | — | | `account.type` | string | sí | **Esquema de identificación** de la cuenta. Aquí solo se admite `IBAN`. No es la clasificación interna de la cuenta (ej. operativa). Values: IBAN | | `account.value` | string | sí | IBAN (se permiten espacios; se normaliza en el servidor) | **200** — La solicitud se procesó correctamente. Campos de `data`: | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `account` | object | sí | — | | `account.type` | string | sí | **Esquema de identificación** de la cuenta (ej. `IBAN`, `PHONE`). No es la clasificación interna de la cuenta (ej. operativa). Values: IBAN, PHONE | | `account.value` | string | sí | Cuando `type` es `PHONE` (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777"). | | `account.currency` | string | no | Moneda opcional de la cuenta en las respuestas. | | `amounts` | object | sí | Saldos del ledger como textos decimales con 2 decimales (misma escala que los montos públicos de pago). Preferí texto sobre número JSON para montos financieros. | | `amounts.available` | string | no | — | | `amounts.posted` | string | no | — | | `amounts.inbound_in_transit` | string | no | — | | `amounts.outbound_in_transit` | string | no | — | | `as_of` | string (date-time) | sí | Marca de tiempo del ledger cuando se conoce (RFC 3339 UTC, precisión de segundos, `Z`); `null` cuando no está disponible. Puede ser null. | **Ejemplo de respuesta** ```json { "success": true, "http_status_code": 200, "response_code": "OK", "message": "The request was processed successfully.", "correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "data": { "account": { "type": "IBAN", "value": "CR26036900101010588061", "currency": "CRC" }, "amounts": { "available": "991900.00", "posted": "991900.00", "inbound_in_transit": "0.00", "outbound_in_transit": "0.00" }, "as_of": "2026-01-15T12:00:00Z" } } ``` **Respuestas de error** | HTTP | response_code | Descripción | |---|---|---| | 400 | `INVALID_REQUEST` | Invalid request. Check the required fields and try again. | | 401 | `UNAUTHORIZED` | Unauthorized. Verify your session or credentials. | | 403 | `FORBIDDEN` | You do not have permission to perform this action. | | 403 | `ACCOUNT_ACCESS_DENIED` | The actor does not have access to the requested account. | | 404 | `ACCOUNT_NOT_FOUND` | Account not found. | | 422 | `ACCOUNT_NOT_CONFIGURED` | This account is not mapped in the system. Please contact support to configure it correctly. | | 422 | `UNPROCESSABLE_ENTITY` | The request is well-formed but cannot be processed due to business rules. | | 500 | `INTERNAL_ERROR` | An unexpected error occurred. Please try again later. | | 502 | `PROVIDER_ERROR` | Unable to complete the request with the payment provider. Please try again later. | | 503 | `SERVICE_UNAVAILABLE` | A required service is temporarily unavailable. Please try again later. | ### Solicitar generación de estado de cuenta [#post-accounts-statements] ```http POST /api/public/v1/accounts/statements ``` Host: `https://api-baas-sandbox.tilopay.com` — requiere `Authorization: Bearer `. Crea una solicitud asíncrona de estado de cuenta para un rango de fechas (máximo 60 días). Identificá la cuenta con `account.type` + `account.value` (esquema de identificación + valor, ej. IBAN). Sigue el estándar público de identificación de cuentas. `account.type` no es la clasificación interna de la cuenta. Devuelve `{request_id, status: PENDING}` de inmediato. Consultá `GET /accounts/statements/{request_id}` para el estado; cuando es `DONE`, la respuesta incluye una `download_url` firmada. Siempre devuelve HTTP 202 (ACCEPTED) con request_id y status PENDING. La generación es asíncrona. Consultá GET /api/public/v1/accounts/statements/{request_id}: HTTP 200 con PENDING, PROCESSING, DONE o ERROR. DONE incluye download_url, válida por 48 horas. **Parámetros** | Parámetro | En | Tipo | Obligatorio | Descripción | |---|---|---|---|---| | `X-Correlation-Id` | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta. Se devuelve como `correlation_id` en el sobre de respuesta. Si lo omitís, la API genera uno y igual lo devuelve. | | `Idempotency-Key` | header | string | no | — | **Cuerpo del request** | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `account` | object | sí | — | | `account.type` | string | sí | **Esquema de identificación** de la cuenta. Aquí solo se admite `IBAN`. No es la clasificación interna de la cuenta (ej. operativa). Values: IBAN | | `account.value` | string | sí | IBAN (se permiten espacios; se normaliza en el servidor) | | `date_from` | string (date-time) | sí | Marca de tiempo RFC 3339 aceptada en solicitudes. Se permite UTC `Z` u offset numérico. Las fracciones de segundo opcionales se aceptan y se truncan a segundos. | | `date_to` | string (date-time) | sí | RFC 3339 (máximo 60 días después de date_from) | | `notify_email` | boolean | no | — | **202** — Solicitud de estado de cuenta aceptada para generación asíncrona. `response_code`: `ACCEPTED` Campos de `data`: | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `request_id` | string (uuid) | sí | — | | `status` | string | sí | Values: PENDING | **Ejemplo de respuesta** ```json { "success": true, "http_status_code": 202, "response_code": "ACCEPTED", "message": "Statement request accepted.", "correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "data": { "request_id": "5f3b2c1d-9e8a-4b7c-8d6e-5f4a3b2c1d0e", "status": "PENDING" } } ``` **Respuestas de error** | HTTP | response_code | Descripción | |---|---|---| | 400 | `INVALID_REQUEST` | Invalid request. Check the required fields and try again. | | 401 | `UNAUTHORIZED` | Unauthorized. Verify your session or credentials. | | 403 | `FORBIDDEN` | You do not have permission to perform this action. | | 403 | `ACCOUNT_ACCESS_DENIED` | The actor does not have access to the requested account. | | 404 | `NOT_FOUND` | The requested resource was not found. | | 409 | `IDEMPOTENCY_CONFLICT` | Idempotency conflict: the same Idempotency-Key was reused with a different request body, or a previous request is still in progress. | | 500 | `INTERNAL_ERROR` | An unexpected error occurred. Please try again later. | | 502 | — | Error de dependencia | | 503 | `SERVICE_UNAVAILABLE` | A required service is temporarily unavailable. Please try again later. | ### Consultar estado de la solicitud de estado de cuenta [#get-accounts-statements-request-id] ```http GET /api/public/v1/accounts/statements/{request_id} ``` Host: `https://api-baas-sandbox.tilopay.com` — requiere `Authorization: Bearer `. Devuelve el estado de la solicitud. Cuando es `DONE`, incluye una `download_url` firmada y temporal (48 h desde su generación) y `expires_at`. Cuando es `ERROR`, incluye un `message` genérico sin detalles internos. Un `request_id` desconocido o no autorizado devuelve 404. Devuelve HTTP 200 con status PENDING, PROCESSING, DONE o ERROR. DONE incluye download_url, válida por 48 horas. **Parámetros** | Parámetro | En | Tipo | Obligatorio | Descripción | |---|---|---|---|---| | `X-Correlation-Id` | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta. Se devuelve como `correlation_id` en el sobre de respuesta. Si lo omitís, la API genera uno y igual lo devuelve. | | `request_id` | path | string (uuid) | sí | — | **200** — La solicitud se procesó correctamente. Campos de `data`: | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `request_id` | string (uuid) | sí | — | | `status` | string | sí | Values: PENDING, PROCESSING, DONE, ERROR | | `download_url` | string (uri) | no | URL de descarga firmada, presente con status DONE; válida por 48 horas desde su generación. | | `expires_at` | string (date-time) | no | Vencimiento de download_url (48 h desde su generación) | | `message` | string | no | Mensaje genérico de error cuando el estado es ERROR | **Ejemplo de respuesta** ```json { "success": true, "http_status_code": 200, "response_code": "OK", "message": "The request was processed successfully.", "correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "data": { "request_id": "5f3b2c1d-9e8a-4b7c-8d6e-5f4a3b2c1d0e", "status": "DONE", "download_url": "https://storage.example.com/statements/5f3b2c1d.pdf?signature=example", "expires_at": "2026-01-17T12:00:00Z", "message": null } } ``` **Respuestas de error** | HTTP | response_code | Descripción | |---|---|---| | 401 | `UNAUTHORIZED` | Unauthorized. Verify your session or credentials. | | 403 | `FORBIDDEN` | You do not have permission to perform this action. | | 404 | `NOT_FOUND` | The requested resource was not found. | | 500 | `INTERNAL_ERROR` | An unexpected error occurred. Please try again later. | | 503 | `SERVICE_UNAVAILABLE` | A required service is temporarily unavailable. Please try again later. | ## Validación y códigos SINPE [#validacion-sinpe] El código `1001` indica que la cuenta existe y está activa: no es un rechazo. `208` significa «Operación no autorizada entre las entidades participantes» y `209`, «Pendientes de Cumplimiento». La validación de cuentas tiene límites de tasa: al superarlos responde `429` (`TOO_MANY_REQUESTS`). Reintentá con espera exponencial. --- # Webhooks del API Bancario > Registro de destino, features suscribibles y contratos de payload de los webhooks del API Bancario. - kind: api-operation - status: stable - api_version: 1.0.0 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/api-bancario/webhooks El grupo `Webhooks` permite registrar el destino HTTPS donde recibís los eventos, ver qué features podés suscribir por método de pago y consultar el contrato de payload de cada evento antes de escribir el receptor. ```http POST /api/public/v1/webhook/destination GET /api/public/v1/webhook/features GET /api/public/v1/webhook/event-contracts/{event_type} ``` ## Eventos [#eventos] Nuestro API te notifica cuatro tipos de evento: | Evento | Cuándo llega | |---|---| | `payin.posted` | Se acreditó un movimiento de entrada. | | `payment.succeeded` | El pago terminó de forma exitosa. | | `payment.failed` | El pago terminó con falla. | | `payment.reversed` | El pago fue revertido. | Un pago revertido conserva el estado `posted` y se distingue por `result: reversed` y `has_reversal: true`; ver [estados del pago](/developers/api-bancario/pagos#estados). ## Buenas prácticas del receptor [#receptor] La entrega se intenta hasta **3 veces por evento** y se considera exitosa con **cualquier HTTP `2xx`**. Respondé `2xx` en cuanto recibís el evento y procesá aparte: un receptor lento provoca reenvíos. Tratá los eventos como potencialmente repetidos y deduplicá por `event.event_id` del sobre (los reintentos reenvían el mismo evento con el mismo `event_id`). Y no confíes el estado final sólo al webhook: confirmalo con [la consulta del pago](/developers/api-bancario/pagos#operaciones). ## Operaciones [#operaciones] ### Crear destino de webhook [#post-webhook-destination] ```http POST /api/public/v1/webhook/destination ``` Host: `https://api-baas-sandbox.tilopay.com` — requiere `Authorization: Bearer `. Los campos válidos dependen de `destination_kind` y `scope_kind`. Enviá solo los campos que aplican a tu combinación; los demás campos de alcance deben omitirse (no como marcadores null). **Payloads de eventos** Inspeccioná los contratos salientes con `GET /api/public/v1/webhook/event-contracts/{event_type}` (`payin.posted`, `payment.succeeded`, `payment.failed`, `payment.reversed`). **destination_kind** - `EXTERNAL_WEBHOOK` (único tipo disponible en el API pública): requiere `webhook_url` (debe empezar con `https://`) y `secret_ref`. Ajustes opcionales de entrega (`timeout_ms`, `max_attempts`). Los payloads siempre van cifrados con `AES_GCM` usando `secret_ref`; el cuerpo HTTP es `{"data":""}`. - `INTERNAL` está reservado para la administración de la plataforma y no puede crearse por este endpoint. **scope_kind** - `TENANT`: omití `scope_account_id`, `scope_owner_type` y `scope_owner_id`. - `ACCOUNT`: enviá `scope_account_id`; omití los campos de owner. - `OWNER`: enviá `scope_owner_type` y `scope_owner_id`; omití `scope_account_id`. `scope_owner_type` es uno de `tenant`, `partner`, `user`, `platform`, `customer` (en minúsculas en el payload). ## Cifrado del webhook (EXTERNAL_WEBHOOK) Las entregas siempre envían `Content-Type: application/json` y `Accept: application/json`. El cuerpo HTTP siempre es `{"data": ""}`. Los bytes decodificados de base64 son: ``` nonce (12 bytes, random) || AES-256-GCM ciphertext || 16-byte auth tag ``` ``` key = SHA256(secret_ref) # 32 bytes → AES-256 wire = base64_decode(data) nonce, sealed = wire[:12], wire[12:] # sealed = ciphertext || tag plaintext = AES-GCM-Open(key, nonce, sealed, additional_data = none) ``` No se usan datos autenticados adicionales (AAD). `plaintext` es el mismo sobre JSON documentado por tipo de evento en `GET /webhook/event-contracts/{event_type}`: descifrá primero y luego aplicá ese contrato. La autenticidad la da la etiqueta de autenticación GCM (el descifrado falla si el cuerpo fue alterado). Deduplicá los reintentos con `event.event_id` del sobre del payload: los reintentos de entrega pueden reenviar el mismo evento con el mismo `event_id`. La entrega se intenta hasta 3 veces por evento. Cualquier respuesta HTTP 2xx se considera exitosa. **Parámetros** | Parámetro | En | Tipo | Obligatorio | Descripción | |---|---|---|---|---| | `X-Correlation-Id` | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta. Se devuelve como `correlation_id` en el sobre de respuesta. Si lo omitís, la API genera uno y igual lo devuelve. | **Cuerpo del request** | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `feature_id` | string (uuid) | sí | Función a suscribir (de `GET /api/public/v1/webhook/features`). Debe existir o la creación falla. | | `is_enabled` | boolean | no | Por defecto true si se omite. | | `destination_kind` | string | sí | La API pública solo acepta `EXTERNAL_WEBHOOK` (callback HTTPS con secreto compartido). Los destinos `INTERNAL` se administran internamente. Values: EXTERNAL_WEBHOOK | | `destination_ref` | string | no | No se usa en la API pública. Reservado para destinos internos. Puede ser null. | | `webhook_url` | string (uri) | no | Obligatorio cuando `destination_kind = EXTERNAL_WEBHOOK` (debe usar `https://`). Puede ser null. | | `secret_ref` | string | no | Obligatorio cuando `destination_kind = EXTERNAL_WEBHOOK`: secreto compartido para descifrar los payloads AES_GCM (`key = SHA256(secret_ref)`). Ver "Cifrado del webhook" en la descripción de esta operación. Puede ser null. | | `signature_algo` | string | no | Fijo en `AES_GCM` para `EXTERNAL_WEBHOOK`. Se omite al crear; se guarda como `AES_GCM`. `HMAC_SHA256` ya no se admite. Puede ser null. Values: AES_GCM | | `replay_window_sec` | integer | no | Reservado para destinos históricos. No se usa en entregas AES_GCM de `EXTERNAL_WEBHOOK`. Puede ser null. | | `timeout_ms` | integer | no | Timeout HTTP de los intentos de entrega (`EXTERNAL_WEBHOOK`). Puede ser null. | | `max_attempts` | integer | no | Intentos de entrega por evento, hasta 3. Puede ser null. | | `scope_kind` | string | sí | - `TENANT`: sin campos de id de alcance. - `ACCOUNT`: enviá solo `scope_account_id`. - `OWNER`: enviá solo `scope_owner_type` y `scope_owner_id`. Values: TENANT, ACCOUNT, OWNER | | `scope_account_id` | string (uuid) | no | Obligatorio cuando `scope_kind` es `ACCOUNT`. Debe omitirse para `TENANT` y `OWNER`. Puede ser null. | | `scope_owner_type` | string | no | Obligatorio cuando `scope_kind` es `OWNER`. Valores permitidos (en minúsculas): `tenant`, `partner`, `user`, `platform`, `customer`. Se omite para `TENANT` y `ACCOUNT`. Puede ser null. | | `scope_owner_id` | string (uuid) | no | Obligatorio cuando `scope_kind` es `OWNER`. Se omite para `TENANT` y `ACCOUNT`. Puede ser null. | **Ejemplo de request** — external_webhook_tenant ```json { "feature_id": "11111111-1111-1111-1111-111111111111", "destination_kind": "EXTERNAL_WEBHOOK", "scope_kind": "TENANT", "webhook_url": "https://example.com/hooks/tilopay", "secret_ref": "whsec_example_shared_secret" } ``` **201** — El recurso se creó correctamente. Campos de `data`: | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `id` | string (uuid) | no | — | | `feature_id` | string (uuid) | no | — | | `is_enabled` | boolean | no | — | | `destination_kind` | string | no | — | | `destination_ref` | string | no | — | | `webhook_url` | string | no | — | | `secret_ref` | string | no | — | | `signature_algo` | string | no | — | | `replay_window_sec` | integer | no | — | | `timeout_ms` | integer | no | — | | `max_attempts` | integer | no | Intentos de entrega por evento, hasta 3. | | `scope_kind` | string | no | — | | `scope_account_id` | string (uuid) | no | — | | `scope_owner_type` | string | no | — | | `scope_owner_id` | string (uuid) | no | — | | `created_at` | string | no | — | | `updated_at` | string | no | — | **Ejemplo de respuesta** ```json { "success": true, "http_status_code": 201, "response_code": "CREATED", "message": "The resource was created successfully.", "correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "data": { "id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8", "feature_id": "11111111-1111-1111-1111-111111111111", "is_enabled": true, "destination_kind": "EXTERNAL_WEBHOOK", "destination_ref": null, "webhook_url": "https://example.com/hooks/tilopay", "secret_ref": "whsec_example_shared_secret", "signature_algo": "AES_GCM", "replay_window_sec": null, "timeout_ms": 10000, "max_attempts": 8, "scope_kind": "TENANT", "scope_account_id": null, "scope_owner_type": null, "scope_owner_id": null, "created_at": "2026-01-15T12:00:00Z", "updated_at": "2026-01-15T12:00:00Z" } } ``` **Respuestas de error** | HTTP | response_code | Descripción | |---|---|---| | 400 | `INVALID_REQUEST` | Invalid request. Check the required fields and try again. | | 401 | `UNAUTHORIZED` | Unauthorized. Verify your session or credentials. | | 403 | `FORBIDDEN` | You do not have permission to perform this action. | | 500 | `INTERNAL_ERROR` | An unexpected error occurred. Please try again later. | | 503 | `SERVICE_UNAVAILABLE` | A required service is temporarily unavailable. Please try again later. | ### Listar funciones de webhook por método de pago [#get-webhook-features] ```http GET /api/public/v1/webhook/features ``` Host: `https://api-baas-sandbox.tilopay.com` — requiere `Authorization: Bearer `. Devuelve los IDs de función y los `event_types` que cada una puede emitir. El alcance del comercio se toma del token de acceso; no enviés `tenant_id`. **Nombres:** los `event_types` usan `payment.*` para resultados a nivel de recurso (`payment.succeeded`, `payment.failed`, `payment.reversed`) y `payin.posted` solo para la dirección entrante (fondos recibidos). No existe `payout.posted` ni eventos `transaction.*`. El objeto JSON entregado siempre es `payment`. Inspeccioná las formas de payload con `GET /api/public/v1/webhook/event-contracts/{event_type}` (`payin.posted`, `payment.succeeded`, `payment.failed`, `payment.reversed`). **Parámetros** | Parámetro | En | Tipo | Obligatorio | Descripción | |---|---|---|---|---| | `X-Correlation-Id` | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta. Se devuelve como `correlation_id` en el sobre de respuesta. Si lo omitís, la API genera uno y igual lo devuelve. | | `country_code` | query | string | no | — | | `payment_method_code` | query | string | no | — | | `webhook_enabled` | query | boolean | no | — | **200** — La solicitud se procesó correctamente. Campos de `data`: | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `items` | array | no | — | | `items[].id` | string (uuid) | sí | — | | `items[].event_types` | array | sí | Tipos de evento públicos que esta función puede emitir. `payment.*` = resultados a nivel de recurso (cualquier dirección). `payin.posted` = solo dirección entrante (fondos recibidos). No existe `payout.posted` ni `transaction.*`. Inspeccioná las formas de payload con `GET /api/public/v1/webhook/event-contracts/{event_type}`. | **Ejemplo de respuesta** ```json { "success": true, "http_status_code": 200, "response_code": "OK", "message": "The request was processed successfully.", "correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "data": { "items": [ { "id": "11111111-1111-1111-1111-111111111111", "event_types": [ "payin.posted", "payment.succeeded", "payment.failed", "payment.reversed" ] } ] } } ``` **Respuestas de error** | HTTP | response_code | Descripción | |---|---|---| | 401 | `UNAUTHORIZED` | Unauthorized. Verify your session or credentials. | | 403 | `FORBIDDEN` | You do not have permission to perform this action. | | 500 | `INTERNAL_ERROR` | An unexpected error occurred. Please try again later. | | 503 | `SERVICE_UNAVAILABLE` | A required service is temporarily unavailable. Please try again later. | ### Contrato de evento de webhook [#get-webhook-event-contracts-event-type] ```http GET /api/public/v1/webhook/event-contracts/{event_type} ``` Host: `https://api-baas-sandbox.tilopay.com` — requiere `Authorization: Bearer `. Devuelve el contrato del payload saliente de webhook para un tipo de evento público (`schema_version` 1.0.0). El objeto del sobre siempre es `payment` (nunca `payin`, `payout` o `transaction`). **Cuándo usar cada nombre** - **payment** — recurso y sobre. Eventos de resultado: `payment.succeeded`, `payment.failed`, `payment.reversed` (tanto PAYIN como PAYOUT). Se correlaciona con `/transactions/payments` de REST. - **payin / payout** — dirección (`PAYIN` entrante, `PAYOUT` saliente). `payin.posted` es solo entrante (registrado en el ledger / fondos recibidos). No existe un `payout.posted` público. - **transaction** — solo prefijo de ruta REST. No se usa en `event_type` ni en los objetos del payload. Valores de `event_type` admitidos: - `payin.posted` — un pago entrante (PAYIN) llegó al estado público `posted`. El campo del sobre es `payment`. `payment.local_payment` es un booleano JSON (`true`/`false`), no una cadena. - `payment.succeeded` — el proveedor confirmó el éxito de un pago (PAYIN o PAYOUT; PIN o SINPE Móvil). Resultado a nivel de recurso, no específico de dirección. - `payment.failed` — el procesamiento terminó en un fallo definitivo (`status=failed` público), con `payment.error` estructurado (`domain` / `platform`). Cuando el proveedor rechazó el pago, el sobre también incluye `rejection`. No se usa para reversos posteriores. - `payment.reversed` — reverso posterior de un pago que ya había avanzado (típicamente `status=posted` o `confirmed`). REST `result=reversed` y `has_reversal=true`. El `status` de procesamiento no cambia. No es un `payment.failed`. Los valores de `event_type` desconocidos (incluido el interno `payment.status_changed`) devuelven `404`. ## Códigos de rechazo SINPE (`rejection`, solo en `payment.failed`) Cuando `event_type = payment.failed` y el proveedor rechazó el pago, el sobre incluye `rejection` (mismo objeto y catálogo que `data.rejection` en `POST /accounts/validate`). `rejection.code` es uno de un conjunto fijo de semánticas normalizadas (ver la tabla de valores más abajo). **La mayoría de filas de la tabla NO tienen un `code` propio**: solo un subconjunto de valores de `reason_code` tiene una semántica dedicada; cualquier otro `reason_code`, incluso uno listado abajo con un `message` específico, devuelve `code = SINPE_REJECTED` (ej. `reason_code = 21` "fondos insuficientes" igual devuelve `SINPE_REJECTED`). Un `reason_code` que no aparece aquí igual produce respuesta: `message` cae a un texto genérico y `code` a `SINPE_REJECTED`. **Cuenta / perfil / límites** | Code | Message | |---|---| | 21 | Cuenta Cliente con fondos insuficientes | | 22 | Cuenta Cliente no admite créditos | | 23 | Cuenta Cliente cerrada | | 24 | Cuenta Cliente inactiva | | 25 | Cuenta Cliente no admite débitos | | 26 | Cuenta Cliente no es de fondos | | 27 | Moneda de la Cuenta Cliente no corresponde | | 28 | Cuenta cliente no existe | | 29 | Cuenta Cliente no registrada en el SINPE | | 30 | Cuenta Cliente no habilitada para el servicio | | 31 | Cuenta Cliente bloqueada | | 32 | Id cliente destino no coincide con registrado en la entidad | | 33 | Nombre del cliente destino no coincide con el registrado en la entidad | | 34 | Cuenta Cliente en proceso de cierre | | 35 | Cuenta Cliente embargada | | 36 | Cuenta Cliente con retención judicial | | 37 | Cuenta de expediente simplificado no permite el monto indicado | | 38 | Límite transaccional de la Cuenta Cliente excedido | | 39 | Cuenta Cliente incorrecta | | 40 | IBAN de la cuenta destino inválido | | 41 | IBAN de la cuenta origen inválido | | 42 | Tipo de cuenta no permite la transacción | | 43 | Cuenta Cliente no pertenece a la entidad indicada | | 44 | Producto de la cuenta no admite el servicio | | 45 | Cuenta Cliente en estado de cancelación | | 46 | Cuenta Cliente restringida por política de la entidad | | 47 | Cuenta Cliente no permite pagos inmediatos | | 48 | Cuenta Cliente no permite SINPE Móvil | | 49 | Titular de la cuenta destino fallecido | | 50 | Cuenta Cliente consolidada o migrada | | 51 | Identificación del cliente origen no coincide | | 52 | Identificación del cliente destino inválida | | 53 | Cliente destino no autorizado para recibir el pago | | 54 | Cliente origen no autorizado para enviar el pago | | 55 | Perfil del cliente origen no permite la transacción | | 56 | Monto inferior al mínimo permitido | | 57 | Monto superior al máximo permitido | | 58 | Cantidad de transacciones diarias excedida | | 59 | Cantidad de transacciones mensuales excedida | | 60 | Límite acumulado diario excedido | | 61 | Límite acumulado mensual excedido | | 62 | Comisión no pudo ser aplicada | | 63 | Tipo de cambio no disponible | | 64 | Transacción rechazada por control de lavado de dinero | | 65 | Transacción rechazada por listas de control | | 66 | Transacción en revisión de cumplimiento | | 67 | Documento de respaldo requerido no presente | | 68 | Firma o autenticación inválida | | 69 | Token o segundo factor inválido | | 70 | Sesión de usuario expirada | | 71 | Usuario no autorizado para el canal | | 72 | Dispositivo no registrado | | 73 | Geolocalización no permitida | | 74 | Operación no soportada en la moneda indicada | | 75 | Operación no soportada para el tipo de cliente | | 76 | Problemas de comunicación | | 77 | Tiempo de espera agotado en la entidad origen | | 78 | Tiempo de espera agotado en el SINPE | | 79 | Error interno de la entidad origen | | 80 | Error interno de la entidad destino | | 81 | Entidad origen no disponible | | 82 | Entidad destino no encontrada | | 83 | Problemas en la respuesta del destino | | 84 | Respuesta de la entidad origen incorrecta | | 85 | Mensaje con formato electrónico inválido | | 86 | Versión del estándar electrónico no soportada | | 87 | Campo obligatorio no informado | | 88 | Campo con valor fuera de catálogo | | 89 | Checksum o integridad del mensaje inválida | | 90 | Referencia SINPE duplicada | | 91 | Moneda no corresponde | | 92 | Transacción no autorizada por entidad destino | | 93 | Transacción no autorizada por cliente destino | | 94 | Transacción no autorizada por entidad origen | | 95 | Transacción no autorizada por cliente origen | | 96 | Reverso no permitido para el estado de la transacción | | 97 | Reverso ya aplicado | | 98 | Confirmación no permitida para el estado de la transacción | | 99 | Liquidación no permitida para el estado de la transacción | | 100 | Entidad Destino no disponible para procesar en tiempo real | | 101 | Entidad origen no disponible para procesar en tiempo real | | 102 | Servicio PIN no habilitado para la entidad destino | | 103 | Servicio PIN no habilitado para la entidad origen | | 104 | Código de entidad destino inválido | | 105 | Código de entidad origen inválido | | 106 | Código de país de la entidad destino inválido | | 107 | Código de país de la entidad origen inválido | | 108 | Número de referencia interna inválido | | 109 | Número de referencia SINPE inválido | | 110 | Transacción no se encuentra en un estado que permita la consulta | **Compensación con entidad destino** | Code | Message | |---|---| | 201 | Tiempo respuesta excedido por la entidad destino | | 202 | Respuesta de la entidad destino incorrecta según el estándar electrónico | | 203 | Se recibió una excepción de la entidad destino | | 204 | Error de comunicación con la entidad destino | | 205 | Falló procesamiento en el SINPE | | 206 | Transacción no autorizada por cliente destino | | 207 | Perfil transaccional del cliente destino no permite recibir el pago | | 208 | Operación no autorizada entre las entidades participantes | | 209 | Pendientes de Cumplimiento | | 210 | Conciliación de la transacción no fue posible | **Identificación** | Code | Message | |---|---| | 801 | Identificación inválida | | 802 | Identificación del cliente origen no encontrada | | 803 | Identificación del cliente destino no encontrada | | 804 | Identificación no vigente | | 805 | Identificación vencida | | 806 | Identificación no corresponde al tipo indicado | | 807 | Tipo de identificación inválido | | 808 | País de la identificación no soportado | | 809 | Identificación de menor de edad no permitida | | 810 | Identificación de persona jurídica no permitida para el servicio | **Validación de formato / Core Bancario** | Code | Message | |---|---| | 1002 | El Id de cliente destino no cumple con el formato esperado por el SINPE | | 1003 | El Id de cliente origen no fue informado | | 1004 | El Id de cliente origen no cumple con el formato esperado por el SINPE | | 1005 | Monto con formato inválido | | 1006 | Moneda con formato inválido | | 1007 | Problemas de comunicación con el Core Bancario | | 1008 | Core Bancario no disponible | | 1009 | El valor para el campo no puede ser nulo o infringir su longitud mínima o máxima | | 1010 | El valor para el campo no corresponde al tipo de dato esperado | | 1011 | El valor para el campo no corresponde al catálogo permitido | | 1012 | Fecha con formato inválido | | 1013 | Hora con formato inválido | | 1014 | Número de referencia con formato inválido | | 1015 | IBAN con formato inválido | **Canal / tipo de identificación** | Code | Message | |---|---| | 1040 | Canal no informado | | 1041 | Canal inválido | | 1042 | Canal no corresponde | | 1043 | Canal no habilitado para la entidad | | 1044 | Canal no habilitado para el servicio | | 1045 | El formato de la identificación es inválido | | 1046 | Tipo de identificación no informado | | 1080 | Tipo de identificación no corresponde al cliente origen | | 1081 | Tipo de identificación no corresponde al cliente destino | | 1082 | Tipo de identificación no vigente | | 1083 | Tipo de identificación no soportado por el servicio | | 1084 | Tipo de identificación inválido | | 1085 | Tipo de identificación no soportado por la entidad | **SINPE Móvil (monedero)** | Code | Message | |---|---| | 15300 | El número de teléfono origen indicado es inválido | | 15301 | El número de teléfono origen no tiene activo el Servicio Monedero | | 15302 | El número de teléfono destino indicado es inválido | | 15303 | El número de teléfono destino no está registrado en el padrón móvil del BCCR | | 15304 | No es posible inactivar el monedero indicado pues no existe | | 15305 | El número de teléfono indicado ya se encuentra activo como monedero en el padrón local | Delivery body is JSON. `EXTERNAL_WEBHOOK` HTTP body is always `{"data":""}` (AES-256-GCM, key = SHA256(secret_ref)). Decrypt to obtain the event envelope documented per `GET /webhook/event-contracts/{event_type}`; the decrypted plaintext matches that contract. **Valores de `rejection.code`** | Valor | Significado | |---|---| | `ACCOUNT_CLOSED` | Cuenta cerrada | | `ACCOUNT_NOT_FOUND` | Cuenta no encontrada | | `ACCOUNT_BLOCKED` | Cuenta bloqueada | | `INVALID_ACCOUNT` | Cuenta inválida | | `IDENT_MISMATCH` | La identificación no coincide | | `IDENT_TYPE_INVALID` | Tipo de identificación inválido | | `INVALID_ID_FORMAT` | Formato de identificación inválido | | `VALIDATION_ERROR` | Error de validación | | `CURRENCY_MISMATCH` | La moneda no corresponde | | `NOT_AUTHORIZED_BY_RECIPIENT` | No autorizado por el destinatario | | `PROFILE_NOT_ALLOWED` | Perfil no permitido | | `CHANNEL_NOT_RECOGNIZED` | Canal no reconocido | | `COMMUNICATION_ERROR` | Error de comunicación | | `RETRY_LATER` | Reintentar más tarde | | `WALLET_PHONE_ORIGIN_INVALID` | Teléfono origen inválido (SINPE Móvil) | | `WALLET_PHONE_ORIGIN_NOT_ENABLED` | Teléfono origen sin servicio de monedero | | `WALLET_PHONE_DEST_INVALID` | Teléfono destino inválido (SINPE Móvil) | | `WALLET_PHONE_NOT_REGISTERED_BCCR` | Teléfono no registrado en el padrón móvil del BCCR | | `WALLET_NOT_FOUND` | Monedero no encontrado | | `WALLET_PHONE_ALREADY_ACTIVE` | El teléfono ya tiene un monedero activo | | `PHONE_NOT_REGISTERED` | Teléfono no registrado | | `SINPE_REJECTED` | Rechazado por SINPE (valor genérico de respaldo) | La entrega se intenta hasta 3 veces por evento. Cualquier respuesta HTTP 2xx se considera exitosa. **Parámetros** | Parámetro | En | Tipo | Obligatorio | Descripción | |---|---|---|---|---| | `X-Correlation-Id` | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta. Se devuelve como `correlation_id` en el sobre de respuesta. Si lo omitís, la API genera uno y igual lo devuelve. | | `event_type` | path | string | sí | Values: payin.posted, payment.succeeded, payment.failed, payment.reversed | **200** — La solicitud se procesó correctamente. Campos de `data`: | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `event_type` | string | sí | Values: payin.posted, payment.succeeded, payment.failed, payment.reversed | | `schema_version` | string | sí | — | | `description` | string | sí | — | | `example` | object | sí | — | **Ejemplo de respuesta** ```json { "success": true, "http_status_code": 200, "response_code": "OK", "message": "The request was processed successfully.", "correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "data": { "event_type": "payment.succeeded", "schema_version": "1.0.0", "description": "Envelope delivered for `payment.succeeded` (decrypt AES_GCM `data` field first).", "example": { "event_id": "evt_01JEXAMPLE", "event_type": "payment.succeeded", "schema_version": "1.0.0" }, "x-description-es": "Sobre entregado para `payment.succeeded` (descifrá primero el campo `data` AES_GCM)." } } ``` **Respuestas de error** | HTTP | response_code | Descripción | |---|---|---| | 401 | `UNAUTHORIZED` | Unauthorized. Verify your session or credentials. | | 403 | `FORBIDDEN` | You do not have permission to perform this action. | | 404 | `NOT_FOUND` | The requested resource was not found. | | 500 | `INTERNAL_ERROR` | An unexpected error occurred. Please try again later. | | 503 | `SERVICE_UNAVAILABLE` | A required service is temporarily unavailable. Please try again later. | ## Contratos de payload [#contratos] Cada evento tiene su propia estructura de datos. Esto es lo que te enviamos en cada uno: ### payin.posted [#contrato-payin-posted] Datos que te enviamos en `payin.posted`. | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `schema_version` | string | sí | — | | `event` | object | sí | — | | `event.event_id` | string (uuid) | sí | — | | `event.event_type` | string | sí | Values: payin.posted | | `event.occurred_at` | string (date-time) | sí | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `event.correlation_id` | string | sí | — | | `context` | object | sí | — | | `context.country_code` | string | sí | — | | `context.payment_method_code` | string | sí | Catálogo público de métodos de pago. Mismos valores que en REST (`PIN`, `SINPE_MOVIL`). Nunca se exponen códigos internos. Values: PIN, SINPE_MOVIL | | `payment` | object | sí | — | | `payment.payment_id` | string (uuid) | sí | — | | `payment.public_id` | integer (int64) | sí | Es el mismo identificador: número en webhooks y texto en REST. Tratalo siempre como texto. | | `payment.status` | string | sí | Catálogo público de estados del pago. Siempre en minúsculas. Mismos valores en REST (crear, listar, obtener) y en webhooks (`payment.status`). Los estados internos del ciclo de vida se consolidan: - `pending`: iniciado, validado, aceptado - `processing`: procesando, pendiente de procesamiento, registrando - `confirmed`: confirmado por el riel, aún no registrado en el ledger - `posted`: registrado en el ledger (se mantiene `posted` tras un reverso posterior) - `failed`: fallido, rechazado, posting_failed, cancelado, expirado Un reverso **no** es un estado. Usá `result=reversed` / `has_reversal=true` en REST y el webhook `payment.reversed`. El detalle operativo queda en `status_detail` (nombre interno en mayúsculas) en crear/listar/obtener de REST. El webhook `payment.failed` usa `error.platform.code` para distinguir fallos de registro de rechazos del proveedor. Values: pending, processing, confirmed, posted, failed | | `payment.amount` | object | sí | — | | `payment.amount.amount` | string | sí | Monto como texto decimal con exactamente 2 decimales (ej. "1000.00"). | | `payment.amount.currency` | string | sí | Moneda ISO 4217 del pago. Values: CRC, USD | | `payment.posted_at` | string (date-time) | sí | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `payment.account` | object | sí | — | | `payment.account.type` | string | sí | — | | `payment.account.value` | string | sí | — | | `payment.reference` | object | sí | — | | `payment.reference.client_reference` | string | sí | Referencia del comercio enviada al crear el pago (`client_reference`), no `detail_reference`. | | `payment.reference.external_reference` | string | sí | — | | `payment.destination_phone_number` | string | no | — | | `payment.local_payment` | boolean | no | Booleano JSON (`true`/`false`), no las cadenas `"true"`/`"false"`. | | `payment.origin_client_name` | string | no | — | | `provider` | object | sí | Foto compartida del proveedor en las lecturas REST de pagos y en los sobres de webhook. La referencia del riel solo está en `payment.external_reference`, no se duplica aquí. Los `provider_status_*` coinciden con `rejection.reason_code` / `message` / `code` del webhook cuando el proveedor rechazó la operación. `null` cuando no hay rechazo. | | `provider.correlation_id` | string | sí | Provider transaction correlation identifier. Sent to SINPE as the correlation id. Not `channel_reference` (e.g. `MOBILE_APP`). Distinct from webhook `event.correlation_id` (HTTP request id for this delivery). `null` when unknown. Puede ser null. | | `provider.occurred_at` | string (date-time) | sí | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `provider.provider_status_code` | string | sí | Motivo/código crudo del proveedor (ej. `31`). Mismo significado que `rejection.reason_code` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `provider.provider_status_desc` | string | sí | Texto Motivo del proveedor (prefiere Detalle). Mismo significado que `rejection.message` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `provider.provider_status_semantic` | string | sí | Semántica normalizada de la plataforma (ej. `ACCOUNT_BLOCKED`). Mismo significado que `rejection.code` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | ### payment.succeeded [#contrato-payment-succeeded] Datos que te enviamos en `payment.succeeded`. | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `schema_version` | string | sí | — | | `event` | object | sí | — | | `event.event_id` | string (uuid) | sí | — | | `event.event_type` | string | sí | Values: payment.succeeded | | `event.occurred_at` | string (date-time) | sí | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `event.correlation_id` | string | sí | — | | `context` | object | sí | — | | `context.country_code` | string | sí | — | | `context.payment_method_code` | string | sí | Catálogo público de métodos de pago. Mismos valores que en REST (`PIN`, `SINPE_MOVIL`). Nunca se exponen códigos internos. Values: PIN, SINPE_MOVIL | | `payment` | object | sí | — | | `payment.payment_id` | string (uuid) | sí | — | | `payment.public_id` | integer (int64) | sí | Es el mismo identificador: número en webhooks y texto en REST. Tratalo siempre como texto. | | `payment.status` | string | sí | Catálogo público de estados del pago. Siempre en minúsculas. Mismos valores en REST (crear, listar, obtener) y en webhooks (`payment.status`). Los estados internos del ciclo de vida se consolidan: - `pending`: iniciado, validado, aceptado - `processing`: procesando, pendiente de procesamiento, registrando - `confirmed`: confirmado por el riel, aún no registrado en el ledger - `posted`: registrado en el ledger (se mantiene `posted` tras un reverso posterior) - `failed`: fallido, rechazado, posting_failed, cancelado, expirado Un reverso **no** es un estado. Usá `result=reversed` / `has_reversal=true` en REST y el webhook `payment.reversed`. El detalle operativo queda en `status_detail` (nombre interno en mayúsculas) en crear/listar/obtener de REST. El webhook `payment.failed` usa `error.platform.code` para distinguir fallos de registro de rechazos del proveedor. Values: pending, processing, confirmed, posted, failed | | `payment.amount` | object | sí | — | | `payment.amount.amount` | string | sí | Monto como texto decimal con exactamente 2 decimales (ej. "1000.00"). | | `payment.amount.currency` | string | sí | Moneda ISO 4217 del pago. Values: CRC, USD | | `payment.client_reference` | string | sí | Referencia del comercio enviada al crear el pago (`client_reference`), no `detail_reference`. | | `payment.external_reference` | string | sí | — | | `payment.fee_total` | string | sí | Total de comisiones como texto decimal (misma moneda que amount.currency) | | `payment.tax_total` | string | sí | Total de impuestos como texto decimal (misma moneda que amount.currency) | | `payment.net_amount` | string | sí | Impacto neto en efectivo en la cuenta del comercio. PAYIN: amount - fee_total - tax_total (lo que recibe el comercio). PAYOUT: amount + fee_total + tax_total (débito total; la comisión se cobra aparte y no se descuenta del monto transferido). | | `payment.succeeded_at` | string (date-time) | sí | Marca de tiempo en que el proveedor confirmó el éxito del pago. | | `provider` | object | sí | Foto compartida del proveedor en las lecturas REST de pagos y en los sobres de webhook. La referencia del riel solo está en `payment.external_reference`, no se duplica aquí. Los `provider_status_*` coinciden con `rejection.reason_code` / `message` / `code` del webhook cuando el proveedor rechazó la operación. `null` cuando no hay rechazo. | | `provider.correlation_id` | string | sí | Provider transaction correlation identifier. Sent to SINPE as the correlation id. Not `channel_reference` (e.g. `MOBILE_APP`). Distinct from webhook `event.correlation_id` (HTTP request id for this delivery). `null` when unknown. Puede ser null. | | `provider.occurred_at` | string (date-time) | sí | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `provider.provider_status_code` | string | sí | Motivo/código crudo del proveedor (ej. `31`). Mismo significado que `rejection.reason_code` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `provider.provider_status_desc` | string | sí | Texto Motivo del proveedor (prefiere Detalle). Mismo significado que `rejection.message` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `provider.provider_status_semantic` | string | sí | Semántica normalizada de la plataforma (ej. `ACCOUNT_BLOCKED`). Mismo significado que `rejection.code` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | ### payment.failed [#contrato-payment-failed] Datos que te enviamos en `payment.failed`. | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `schema_version` | string | sí | — | | `event` | object | sí | — | | `event.event_id` | string (uuid) | sí | — | | `event.event_type` | string | sí | Values: payment.failed | | `event.occurred_at` | string (date-time) | sí | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `event.correlation_id` | string | sí | — | | `context` | object | sí | — | | `context.country_code` | string | sí | — | | `context.payment_method_code` | string | sí | Catálogo público de métodos de pago. Mismos valores que en REST (`PIN`, `SINPE_MOVIL`). Nunca se exponen códigos internos. Values: PIN, SINPE_MOVIL | | `payment` | object | sí | — | | `payment.payment_id` | string (uuid) | sí | — | | `payment.public_id` | integer (int64) | sí | Es el mismo identificador: número en webhooks y texto en REST. Tratalo siempre como texto. | | `payment.status` | string | sí | Catálogo público de estados del pago. Siempre en minúsculas. Mismos valores en REST (crear, listar, obtener) y en webhooks (`payment.status`). Los estados internos del ciclo de vida se consolidan: - `pending`: iniciado, validado, aceptado - `processing`: procesando, pendiente de procesamiento, registrando - `confirmed`: confirmado por el riel, aún no registrado en el ledger - `posted`: registrado en el ledger (se mantiene `posted` tras un reverso posterior) - `failed`: fallido, rechazado, posting_failed, cancelado, expirado Un reverso **no** es un estado. Usá `result=reversed` / `has_reversal=true` en REST y el webhook `payment.reversed`. El detalle operativo queda en `status_detail` (nombre interno en mayúsculas) en crear/listar/obtener de REST. El webhook `payment.failed` usa `error.platform.code` para distinguir fallos de registro de rechazos del proveedor. Values: pending, processing, confirmed, posted, failed | | `payment.amount` | object | sí | — | | `payment.amount.amount` | string | sí | Monto como texto decimal con exactamente 2 decimales (ej. "1000.00"). | | `payment.amount.currency` | string | sí | Moneda ISO 4217 del pago. Values: CRC, USD | | `payment.client_reference` | string | no | Referencia del comercio enviada al crear el pago (`client_reference`), no `detail_reference`. | | `payment.external_reference` | string | no | — | | `payment.error` | object | sí | — | | `payment.error.domain` | string | sí | Values: provider_rejection, platform_validation, platform_posting, platform_infra, platform_reversal, sinpe_rejection | | `payment.error.platform` | object | sí | — | | `provider` | object | sí | Foto compartida del proveedor en las lecturas REST de pagos y en los sobres de webhook. La referencia del riel solo está en `payment.external_reference`, no se duplica aquí. Los `provider_status_*` coinciden con `rejection.reason_code` / `message` / `code` del webhook cuando el proveedor rechazó la operación. `null` cuando no hay rechazo. | | `provider.correlation_id` | string | sí | Provider transaction correlation identifier. Sent to SINPE as the correlation id. Not `channel_reference` (e.g. `MOBILE_APP`). Distinct from webhook `event.correlation_id` (HTTP request id for this delivery). `null` when unknown. Puede ser null. | | `provider.occurred_at` | string (date-time) | sí | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `provider.provider_status_code` | string | sí | Motivo/código crudo del proveedor (ej. `31`). Mismo significado que `rejection.reason_code` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `provider.provider_status_desc` | string | sí | Texto Motivo del proveedor (prefiere Detalle). Mismo significado que `rejection.message` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `provider.provider_status_semantic` | string | sí | Semántica normalizada de la plataforma (ej. `ACCOUNT_BLOCKED`). Mismo significado que `rejection.code` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `rejection` | object | no | Rechazo del proveedor independiente del riel. Compartido por `POST /accounts/validate` (`data.rejection`) y el webhook `payment.failed` (`rejection`). Objeto solo cuando el proveedor rechazó la operación; omitido/`null` en caso contrario. | | `rejection.code` | string | sí | Semántica normalizada de la plataforma derivada de `reason_code`. Solo un subconjunto de valores de `reason_code` (ver el catálogo en la descripción de `POST /accounts/validate` y del endpoint de contrato del webhook `payment.failed`) tiene entrada propia aquí; para cualquier otro `reason_code` numérico, `code` es `SINPE_REJECTED` aunque `message` sea específico (ej. `reason_code = 21` "fondos insuficientes" igual devuelve `code = SINPE_REJECTED`, no tiene semántica propia). `PHONE_NOT_REGISTERED` es el valor de respaldo cuando `reason_code` no es numérico (flujo del monedero SINPE_MOVIL). Values: ACCOUNT_CLOSED, ACCOUNT_NOT_FOUND, ACCOUNT_BLOCKED, INVALID_ACCOUNT, IDENT_MISMATCH, IDENT_TYPE_INVALID, INVALID_ID_FORMAT, VALIDATION_ERROR, CURRENCY_MISMATCH, NOT_AUTHORIZED_BY_RECIPIENT, PROFILE_NOT_ALLOWED, CHANNEL_NOT_RECOGNIZED, COMMUNICATION_ERROR, RETRY_LATER, WALLET_PHONE_ORIGIN_INVALID, WALLET_PHONE_ORIGIN_NOT_ENABLED, WALLET_PHONE_DEST_INVALID, WALLET_PHONE_NOT_REGISTERED_BCCR, WALLET_NOT_FOUND, WALLET_PHONE_ALREADY_ACTIVE, PHONE_NOT_REGISTERED, SINPE_REJECTED | | `rejection.reason_code` | string | sí | Motivo/código crudo devuelto por SINPE. El catálogo completo está en la descripción de `POST /accounts/validate` (lo comparte este objeto dondequiera que aparezca, incluido el webhook `payment.failed`). Un código no listado igual produce respuesta: `message` cae a un texto genérico y `code` a `SINPE_REJECTED`. | | `rejection.message` | string | sí | Texto descriptivo del Motivo; prefiere el `Detalle` del proveedor cuando existe. | ### payment.reversed [#contrato-payment-reversed] Datos que te enviamos en `payment.reversed`. | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `schema_version` | string | sí | — | | `event` | object | sí | — | | `event.event_id` | string (uuid) | sí | — | | `event.event_type` | string | sí | Values: payment.reversed | | `event.occurred_at` | string (date-time) | sí | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `event.correlation_id` | string | sí | — | | `context` | object | sí | — | | `context.country_code` | string | sí | — | | `context.payment_method_code` | string | sí | Catálogo público de métodos de pago. Mismos valores que en REST (`PIN`, `SINPE_MOVIL`). Nunca se exponen códigos internos. Values: PIN, SINPE_MOVIL | | `payment` | object | sí | — | | `payment.payment_id` | string (uuid) | sí | — | | `payment.public_id` | integer (int64) | sí | Es el mismo identificador: número en webhooks y texto en REST. Tratalo siempre como texto. | | `payment.status` | string | sí | Catálogo público de estados del pago. Siempre en minúsculas. Mismos valores en REST (crear, listar, obtener) y en webhooks (`payment.status`). Los estados internos del ciclo de vida se consolidan: - `pending`: iniciado, validado, aceptado - `processing`: procesando, pendiente de procesamiento, registrando - `confirmed`: confirmado por el riel, aún no registrado en el ledger - `posted`: registrado en el ledger (se mantiene `posted` tras un reverso posterior) - `failed`: fallido, rechazado, posting_failed, cancelado, expirado Un reverso **no** es un estado. Usá `result=reversed` / `has_reversal=true` en REST y el webhook `payment.reversed`. El detalle operativo queda en `status_detail` (nombre interno en mayúsculas) en crear/listar/obtener de REST. El webhook `payment.failed` usa `error.platform.code` para distinguir fallos de registro de rechazos del proveedor. Values: pending, processing, confirmed, posted, failed | | `payment.result` | string | sí | Values: reversed | | `payment.has_reversal` | boolean | sí | Values: true | | `payment.amount` | object | sí | — | | `payment.amount.amount` | string | sí | Monto como texto decimal con exactamente 2 decimales (ej. "1000.00"). | | `payment.amount.currency` | string | sí | Moneda ISO 4217 del pago. Values: CRC, USD | | `payment.client_reference` | string | no | — | | `payment.external_reference` | string | no | — | | `payment.reversed_at` | string (date-time) | sí | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `payment.reason` | object | no | — | | `payment.reason.code` | string | no | — | | `payment.reason.message` | string | no | — | | `provider` | object | sí | Foto compartida del proveedor en las lecturas REST de pagos y en los sobres de webhook. La referencia del riel solo está en `payment.external_reference`, no se duplica aquí. Los `provider_status_*` coinciden con `rejection.reason_code` / `message` / `code` del webhook cuando el proveedor rechazó la operación. `null` cuando no hay rechazo. | | `provider.correlation_id` | string | sí | Provider transaction correlation identifier. Sent to SINPE as the correlation id. Not `channel_reference` (e.g. `MOBILE_APP`). Distinct from webhook `event.correlation_id` (HTTP request id for this delivery). `null` when unknown. Puede ser null. | | `provider.occurred_at` | string (date-time) | sí | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo `Z`. Nunca se emiten fracciones de segundo. Ejemplo: `2026-01-15T12:00:00Z`. | | `provider.provider_status_code` | string | sí | Motivo/código crudo del proveedor (ej. `31`). Mismo significado que `rejection.reason_code` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `provider.provider_status_desc` | string | sí | Texto Motivo del proveedor (prefiere Detalle). Mismo significado que `rejection.message` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | | `provider.provider_status_semantic` | string | sí | Semántica normalizada de la plataforma (ej. `ACCOUNT_BLOCKED`). Mismo significado que `rejection.code` del webhook. `null` cuando no hay rechazo del proveedor. Puede ser null. | ## Identificador público [#public-id] `payment.public_id` llega como número en el webhook y como texto en REST; es el mismo identificador. **Tratalo siempre como texto.** --- # Catálogos del API Bancario > Catálogo de tipos de identificación de cliente por país en el API Bancario. - kind: api-operation - status: stable - api_version: 1.0.0 - last_verified: 2026-10-20 - url: https://tilopay.com/developers/api-bancario/catalogos El grupo `Catalogs` publica los valores que tu integración debe usar en los campos de identificación de cliente, en vez de codificarlos a mano. ```http GET /api/public/v1/catalogs/customer-identification-types ``` Filtrá por `country_code` de dos letras para obtener los tipos vigentes en ese país. Consultá el catálogo al iniciar la integración y cacheá el resultado; leelo de nuevo antes de agregar un país nuevo. ## Operaciones [#operaciones] ### Listar tipos de persona para identificación de clientes [#get-catalogs-customer-identification-types] ```http GET /api/public/v1/catalogs/customer-identification-types ``` Host: `https://api-baas-sandbox.tilopay.com` — requiere `Authorization: Bearer `. Devuelve los tipos de persona disponibles (`individual`, `business`, `both`) para el comercio autenticado, opcionalmente filtrados por país. Es una clasificación de tipo de persona, no el catálogo de documentos de identificación de pagos (`cedula`, `juridica`, `dimex`, ...) que usa `identification.type` en `POST /payments`. **Parámetros** | Parámetro | En | Tipo | Obligatorio | Descripción | |---|---|---|---|---| | `X-Correlation-Id` | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta. Se devuelve como `correlation_id` en el sobre de respuesta. Si lo omitís, la API genera uno y igual lo devuelve. | | `country_code` | query | string | no | Código de país ISO-2 opcional para filtrar resultados. También se acepta el parámetro histórico `country` como alias cuando `country_code` no se envía; preferí `country_code`. | **200** — La solicitud se procesó correctamente. Campos de `data`: | Campo | Tipo | Obligatorio | Descripción | |---|---|---|---| | `items` | array | sí | — | | `items[].code` | string | sí | Values: individual, business, both | **Ejemplo de respuesta** ```json { "success": true, "http_status_code": 200, "response_code": "OK", "message": "The request was processed successfully.", "correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "data": { "items": [ { "code": "individual" }, { "code": "business" }, { "code": "both" } ] } } ``` **Respuestas de error** | HTTP | response_code | Descripción | |---|---|---| | 401 | `UNAUTHORIZED` | Unauthorized. Verify your session or credentials. | | 403 | `FORBIDDEN` | You do not have permission to perform this action. | | 500 | `INTERNAL_ERROR` | An unexpected error occurred. Please try again later. | | 502 | — | Error de dependencia | | 503 | `SERVICE_UNAVAILABLE` | A required service is temporarily unavailable. Please try again later. | --- # Códigos de respuesta del API Bancario > Catálogo completo de response_code del API Bancario de Tilopay y cómo reaccionar a cada familia. - kind: concept - status: stable - api_version: 1.0.0 - last_verified: 2026-10-22 - url: https://tilopay.com/developers/api-bancario/errores Todo error del API Bancario llega en el [envelope estándar](/developers/api-bancario/convenciones#envelope), con `success: false`, el status HTTP en `http_status_code` y un `response_code` del catálogo. Ramificá por `response_code`. ## Cómo reaccionar por familia [#familias] **`4xx` de request.** El cuerpo o los parámetros no son válidos, o el recurso no existe. Corregí la llamada antes de reenviarla: reintentar igual devuelve el mismo error. Acá caen `INVALID_REQUEST`, `NOT_FOUND` y los códigos de negocio como `INSUFFICIENT_FUNDS` o `LIMIT_EXCEEDED`. **`401` y `403`.** El token no viaja, venció o su contexto no autoriza el recurso. Renová el access token repitiendo [login e intercambio](/developers/api-bancario/autenticacion#login); si persiste con un token nuevo, el contexto no tiene permiso sobre ese recurso. **`409 IDEMPOTENCY_CONFLICT`.** Reusaste una `Idempotency-Key` con un cuerpo distinto. Usá una llave nueva para la nueva intención; ver [reintentos seguros](/developers/api-bancario/convenciones#reintentos). **`429 TOO_MANY_REQUESTS`.** Hoy aplica en autenticación y validación de cuentas. Espaciá los envíos y reintentá con espera exponencial. **`5xx`.** Falla del lado del servicio. Reintentá con backoff, y en los `POST` reenviá la **misma** `Idempotency-Key` para no duplicar el registro. Guardá el `correlation_id` antes de escalar a soporte. ## Catálogo completo [#catalogo] Estos son los valores de `ResponseCode` que retorna nuestro API, con los status HTTP en los que aparecen. `OK`, `CREATED` y `ACCEPTED` identifican respuestas exitosas; la solicitud asíncrona de estados de cuenta usa `202 ACCEPTED`. | response_code | Status HTTP en que se retorna | |---|---| | `OK` | — | | `CREATED` | — | | `ACCEPTED` | 202 | | `UNAUTHORIZED` | 401 | | `FORBIDDEN` | 403 | | `TOO_MANY_REQUESTS` | 429 | | `SERVICE_UNAVAILABLE` | 503 | | `INTERNAL_ERROR` | 500 | | `INVALID_REQUEST` | 400 | | `ACCOUNT_ACCESS_DENIED` | 403 | | `PROVIDER_ERROR` | 502 | | `INVALID_CREDENTIALS` | 401 | | `NOT_FOUND` | 404 | | `ACCOUNT_NOT_FOUND` | 404 | | `ACCOUNT_NOT_CONFIGURED` | 422 | | `UNPROCESSABLE_ENTITY` | 422 | | `PAYMENT_NOT_FOUND` | 404 | | `INVALID_ACCOUNT_TYPE` | 400 | | `INVALID_ACCOUNT_FORMAT` | 400 | | `INVALID_PAYMENT_METHOD` | 400 | | `PAYMENT_INVALID_PAYLOAD` | 400 | | `ACCOUNT_INVALID` | 400 | | `ACCOUNT_HOLDER_MISMATCH` | 400 | | `IDEMPOTENCY_CONFLICT` | 409 | | `PAYMENT_DUPLICATE` | 409 | | `CONFLICT` | 409 | | `INSUFFICIENT_FUNDS` | 422 | | `LIMIT_EXCEEDED` | 422 | Un `response_code` que no esté en esta lista no forma parte del contrato de la versión 1.0.0 del API: tratalo como error genérico según su status HTTP y reportalo con el `correlation_id`. --- # Agentes de IA > Índice de la sección de agentes de IA: servidor MCP, conexión, permisos, recetas, skills, asistente de WhatsApp, agente de depuración y documentación legible por máquina. - kind: guide - status: stable - last_verified: 2026-10-20 - url: https://tilopay.com/developers/agentes ## Leer [#leer] Todo el portal está disponible en formato legible por máquina: el índice [`llms.txt`](https://tilopay.com/llms.txt), el Markdown crudo de cualquier URL del sitio agregándole `.md`, el [`openapi.json`](/developers/openapi.json) del API y el [`mcp.json`](/developers/mcp.json) del servidor MCP. ## Automatizá la operativa de tu negocio [#actuar] El [servidor MCP](/developers/agentes/mcp) le permite a tu asistente operar tu cuenta de Tilopay: consultar ventas, crear enlaces de pago, reembolsar. El acceso es autoservicio —iniciás sesión con tus credenciales de Tilopay— y tus credenciales nunca salen del servidor de Tilopay. ## Integrar en producto [#integrar] Cuando lo que se construye es un producto que cobra, el camino son el [SDK JavaScript](/developers/sdk) y el [API Adquirencia](/developers/api/autenticacion), no el MCP. ## En esta sección [#indice] - [Servidor MCP](/developers/agentes/mcp) — qué es, cómo se obtiene el acceso y cómo se conecta. - [Conectar tu agente](/developers/agentes/mcp/conectar) — Claude, ChatGPT, Copilot, Cursor, Gemini y otros clientes, paso a paso. - [Qué puede hacer un agente](/developers/agentes/mcp/permisos) — alcance, herramientas sensibles y las confirmaciones que exige Tilopay. - [Recetas](/developers/agentes/mcp/recetas) — flujos de punta a punta listos para copiar. - [Skills](/developers/agentes/mcp/skills) — esas recetas empaquetadas e instalables. - [Asistente de WhatsApp](/developers/agentes/asistente-whatsapp) — el asistente de Tilopay dentro de WhatsApp, sin instalar nada. - [Documentación legible por máquina](/developers/agentes/documentacion-legible) — llms.txt, Markdown crudo, OpenAPI y mcp.json. El **agente de depuración** es el panel lateral de este portal: se abre con el botón de la barra superior y responde con la documentación verificada, cita la página exacta y orienta sobre qué camino de integración corresponde. ## Cuál elegir [#cual-elegir] - Operar la cuenta desde un asistente → [servidor MCP](/developers/agentes/mcp). - Construir un producto que cobra → [API](/developers/api/autenticacion) y [SDK](/developers/sdk). - Alimentar un agente con la documentación → [documentación legible](/developers/agentes/documentacion-legible). El acceso al MCP es autoservicio: se instala el conector y se inicia sesión con las credenciales de Tilopay, como explica la [página del servidor MCP](/developers/agentes/mcp). --- # Asistente de Tilopay en WhatsApp > Qué es el Asistente de Tilopay en WhatsApp, cómo se activa, cómo se usa y qué puede hacer: ventas, transacciones, enlaces de pago, catálogo, microtienda y pedidos, comprobantes, suscripciones, tarjetas guardadas, recordatorios y avisos. - kind: guide - status: stable - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/asistente-whatsapp ## Qué es [#que-es] El Asistente de Tilopay en WhatsApp es el mismo servidor MCP de Tilopay conectado a un chat de WhatsApp. En vez de configurar un cliente MCP, el comercio le escribe en lenguaje natural desde el WhatsApp que ya usa y el asistente ejecuta las herramientas sobre su cuenta de Tilopay. Las capacidades son las mismas que expone el MCP: lo que un agente puede hacer por [herramientas de adquirencia](/developers/agentes/mcp/adquirencia) y, bajo solicitud, por [herramientas bancarias](/developers/agentes/mcp/api-bancario), el asistente lo puede hacer desde el chat. No es un chatbot de respuestas armadas: consulta y opera datos reales de la cuenta, y responde en texto plano pensado para leerse en el teléfono. ## Cómo se activa [#activacion] La vinculación se hace desde el mismo chat de WhatsApp y toma alrededor de un minuto. El comercio debe estar afiliado a Tilopay y la persona necesita su correo y contraseña de Tilopay. 1. Escribí cualquier mensaje al número oficial de Tilopay, **+506 7098 2131**, o abrí el chat directo: [Abrir chat en WhatsApp](https://wa.me/50670982131). Si el número todavía no está vinculado, el chat muestra una bienvenida con el botón **Vincular mi cuenta**. También podés escribir «vincular mi cuenta» para pedir el botón de nuevo. 2. Tocá **Vincular mi cuenta**. Las credenciales y los códigos se ingresan en el formulario seguro que se abre, nunca como mensajes dentro del chat. 3. Ingresá el mismo correo y contraseña que usás para entrar al panel de Tilopay. 4. Si tu cuenta tiene verificación en dos pasos, escribí el código que Tilopay envía al método mostrado en pantalla. 5. Escribí el código de 6 dígitos que llega al correo de Tilopay. Este último código se solicita siempre para confirmar la vinculación. 6. Si tu usuario tiene varios comercios, elegí cuál querés usar. Al terminar, cerrá el formulario y ya podés pedirle al asistente que consulte u opere esa cuenta. La vinculación se autentica con el correo, la contraseña y el código que llega al correo, no con el número: el comercio puede escribir desde cualquier teléfono. El +506 7098 2131 es el mismo número desde el que Tilopay envía los códigos de verificación; pedile al comercio que lo guarde como contacto. Un número sin cuenta vinculada no puede ejecutar consultas ni operaciones. La bienvenida de vinculación se envía como máximo una vez al día; aunque no vuelva a aparecer ese día, podés pedir el botón escribiendo «vincular mi cuenta». ## Volver a vincular la cuenta [#revincular] Si la sesión deja de funcionar o cambia la contraseña, escribí «vincular mi cuenta» y completá el mismo proceso. Volver a vincular el mismo número actualiza la conexión existente: no crea otro perfil ni desconecta los clientes MCP que ya estén vinculados. Cada canal conserva su propia sesión, por lo que un problema en WhatsApp no cierra automáticamente las sesiones de Claude, ChatGPT, Cursor u otros clientes MCP. ## Cómo se usa [#uso] No hay comandos ni menús. Se escribe como se le hablaría a alguien del equipo: - «¿cómo van las ventas de los últimos 30 días?» - «cobrale 25 mil colones a Ana por la consulta y mandámelo por WhatsApp» - «buscá la orden 10432» - «todos los días a las 8pm mandame el resumen de ventas de hoy» El asistente recuerda los últimos mensajes del hilo, así que se puede seguir la conversación sin repetir los datos («mandálo también por correo», «eliminá ese enlace»). ## Qué puede hacer [#capacidades] | Área | Qué resuelve desde el chat | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Ventas | Resumen y tendencias por día, semana o mes, y análisis con ticket promedio, tasa de aprobación, mejores clientes y motivos de rechazo. | | Transacciones | Listar y consultar transacciones, y capturar, reembolsar o reversar un cobro. | | Enlaces de pago | Crear un enlace, compartirlo por WhatsApp o correo, ver su detalle y eliminarlo. | | Catálogo | Listar productos o servicios, ver su detalle, crear, cambiar o eliminar un ítem. | | Microtienda | Armar una tienda con carrito a partir de los productos del catálogo, listar las tiendas activas y desactivar una. | | Pedidos | Activar la gestión de pedidos con nombre y logo de la tienda, ver el resumen, listar pedidos por estado, ver los pagados sin entregar y marcarlos como entregados. | | Comprobantes | Listar los comprobantes de los cobros aprobados y reenviarle a un cliente el comprobante de su pago. | | Contactos | Guardar, listar y eliminar contactos para cobrarles por nombre. | | Cobros recurrentes | Crear, editar y eliminar planes, armarlos paso a paso desde el chat, generar el enlace de suscripción, consultar suscriptores y sus pagos, editar, pausar, reactivar o eliminar un suscriptor, ver cobros fallidos, generar el enlace para poner al día un cobro rechazado y administrar cupones. | | Tarjetas guardadas | Tokenizar la tarjeta de un cliente, listar o eliminar sus tarjetas, consultar métodos de pago y cuotas, cobrar a una tarjeta guardada y ver grupos, afiliados y cobros masivos. | | Recordatorios | Programar recordatorios de una sola vez, diarios, semanales o mensuales, que además pueden ejecutar una consulta del asistente al enviarse; listarlos y cancelarlos. Máximo 20 activos. | | Avisos | Prender, apagar y consultar los avisos del comercio: cobros aprobados, cobros rechazados, pedidos y el resumen diario a la hora que elija. | | Perfil y recetas | Guardar el perfil del negocio y recibir recomendaciones de automatización según lo que vende. | | Soporte | Buscar la guía oficial de un tema, correr el diagnóstico de conexión y revisar un error de integración. | | Bancario (bajo solicitud) | Cuentas, saldos, pagos, estados de cuenta y análisis de movimientos; y, con confirmación por correo, validar una cuenta destino, enviar una transferencia y consultar su estado. Solo con credenciales del API bancario. | Hoy son 117 herramientas en 15 grupos. El detalle de parámetros y el nivel de acceso de cada una vive en las páginas del [servidor MCP](/developers/agentes/mcp). El asistente también recibe **imágenes** por el chat: por ejemplo, la foto de un producto para el catálogo o el logo que se muestra en la microtienda y en los comprobantes. ## Autorización de operaciones sensibles [#autorizacion] Las operaciones que mueven dinero o alteran cobros —reembolsos, capturas, reversiones, cobros a tarjetas guardadas, cambios a suscriptores, eliminación de enlaces, productos o planes y el envío de una transferencia bancaria— piden un código de 6 dígitos que Tilopay envía al correo registrado del usuario. Sin ese código el asistente no las ejecuta. Las llaves del comercio nunca viajan por el chat y el asistente no muestra credenciales, tokens ni identificadores internos. Cada consulta y cada operación queda auditada con usuario, herramienta, fecha y resultado, con límites de uso por cuenta. ## Avisos que el asistente manda solo [#avisos] - **Pago recibido:** cuando un cliente paga un enlace creado desde el asistente, llega un mensaje por WhatsApp con monto, cliente, concepto, referencia y número de orden. - **Reportes programados:** el resumen o la consulta que se haya agendado, con el dato ya consultado al momento del envío. - **Recordatorios:** el recordatorio agendado, con el resultado de la consulta adjunta si se pidió una acción. Los recordatorios de cobros o enlaces siempre llegan al WhatsApp del comercio, nunca al cliente. - **Pedidos por entregar:** el recordatorio diario de los pedidos ya pagados que siguen sin entregar, cuando la gestión de pedidos está activa. ## Si preferís tu propio agente [#mcp] Las mismas herramientas están disponibles por MCP para Claude, ChatGPT, Cursor u otro cliente: empezá por [Conectar tu agente](/developers/agentes/mcp/conectar) y por [Permisos](/developers/agentes/mcp/permisos). --- # Servidor MCP de Tilopay > Cómo conectar un cliente MCP al servidor de Tilopay con OAuth y las mismas credenciales de la cuenta de Tilopay. - kind: mcp-index - status: stable - last_verified: 2026-10-20 - url: https://tilopay.com/developers/agentes/mcp ## Cómo se obtiene el acceso [#acceso] El acceso es autoservicio, el comercio instala el conector con la URL del servidor y, en la ventana de autorización, inicia sesión con las mismas credenciales de su cuenta de Tilopay (correo y contraseña) y confirma el código de verificación que Tilopay envía. Con eso el usuario del asistente se crea solo, queda asociado al comercio y sus credenciales de API se registran cifradas del lado del servidor. Tres cosas que conviene tener claras: 1. La sesión se autoriza con el correo y la contraseña del panel de Tilopay, más el código de verificación. El asistente nunca ve ni guarda esa contraseña: la conexión queda con OAuth 2.0. 2. Como el usuario queda asociado a un comercio, el agente sólo alcanza los datos y las operaciones de ese comercio. 3. El comercio nunca pega su `apiKey`, `apiUser` ni `apiPassword` en el cliente MCP. > **Advertencia:** Las credenciales de API del comercio viven cifradas en el servidor de Tilopay y se descifran en > cada llamada. No se pegan en el cliente MCP, ni en el archivo de configuración del asistente, ni > se le pasan al modelo. Ese es el argumento de seguridad de todo el diseño. ## Conexión [#conexion] El servidor es `https://mcp.tilopay.com/mcp`. Para conectarlo: 1. Agregar el servidor en el cliente MCP con esa URL. 2. El cliente descubre la autenticación por el 401 con `WWW-Authenticate`, que apunta a `/.well-known/oauth-protected-resource`. 3. El cliente se registra dinámicamente y abre la pantalla de autorización. 4. El usuario inicia sesión con las credenciales de su cuenta de Tilopay, confirma el código de verificación y ve una pantalla de consentimiento con la aplicación que pide acceso, la URL de retorno y los permisos. 5. Al aprobar, el cliente queda conectado. El modelo es OAuth 2.0 con `authorization_code` y `refresh_token`. El cliente descubre los endpoints del proveedor de identidad por sí mismo: lo único que hay que configurar es la URL del servidor. ## Desde los clientes MCP más usados [#clientes] - **Claude** (escritorio y web): agregar un conector remoto con la URL del servidor y completar el inicio de sesión en la ventana que abre. Conectar con Claude - **ChatGPT**: agregar el servidor como conector remoto con esa misma URL; la autorización se completa en el navegador. - **Cursor, VS Code y otros editores**: declarar un servidor MCP remoto de tipo HTTP con la URL, sin token en el archivo de configuración; el editor abre el navegador para autorizar. - **Cliente propio**: usar un cliente MCP con transporte Streamable HTTP y soporte de OAuth 2.0 con registro dinámico. La secuencia es la de arriba: 401, descubrimiento, registro, autorización, conexión. ¿Quieres empezar con casos listos? [Instala una skill](/developers/agentes/mcp/skills). El transporte es Streamable HTTP. Las herramientas disponibles se organizan en 15 grupos: los 14 del [API de adquirencia](/developers/agentes/mcp/adquirencia) (lista completa) y el grupo [API bancario (BaaS)](/developers/agentes/mcp/api-bancario), que se activa bajo solicitud y sólo funciona para usuarios con credenciales del API bancario de Tilopay. Antes de conectar un agente, leé [qué puede hacer](/developers/agentes/mcp/permisos). ## Fechas en UTC [#fechas-utc] Para las consultas de ventas, enviá `startDate` y `endDate` en UTC con formato `YYYY-MM-DD HH:mm:ss`, no en hora local. Costa Rica es UTC-6: el día local 2026-10-20 va de `2026-10-20 06:00:00` a `2026-10-21 05:59:59` UTC. Al comparar períodos, convertí primero el rango local a UTC. Siguiente paso → [Conectar tu agente](/developers/agentes/mcp/conectar). --- # Conectar tu agente de IA > Cómo conectar Claude, ChatGPT, GitHub Copilot, Cursor, Gemini u otro cliente MCP al servidor MCP de Tilopay. - kind: guide - status: stable - last_verified: 2026-10-20 - url: https://tilopay.com/developers/agentes/mcp/conectar Todos los agentes se conectan al mismo servidor y con el mismo flujo: se agrega un servidor MCP remoto con la URL de Tilopay y la sesión se autoriza en el navegador. Lo único que cambia entre agentes es dónde se agrega. ```text https://mcp.tilopay.com/mcp ``` La versión del servidor MCP en producción es **0.3.0**. ## Antes de conectar [#antes] 1. No hay formulario ni aprobación previa: basta tener una cuenta activa de Tilopay. 2. Al autorizar, la sesión se inicia con el correo y la contraseña del panel de Tilopay y se confirma el código de verificación que Tilopay envía. El usuario del asistente se crea solo en ese momento y queda asociado al comercio. 3. Revisá [qué puede hacer un agente](/developers/agentes/mcp/permisos) antes de conectarlo, sobre todo las herramientas marcadas como sensibles. > **Advertencia:** Nunca pegues `apiKey`, `apiUser` ni `apiPassword` del comercio en el agente ni en su archivo de > configuración. Las credenciales del comercio viven cifradas en el servidor de Tilopay: el agente > sólo maneja su propia sesión OAuth. ## Claude [#claude] Claude soporta conectores remotos, tanto en la app de escritorio como en la web. 1. Agregá un conector personalizado remoto con la URL del servidor. 2. Claude abre la pantalla de autorización de Tilopay: iniciá sesión con tus credenciales de Tilopay y confirmá el código de verificación. 3. Revisá la pantalla de consentimiento (aplicación que pide acceso, URL de retorno y permisos) y aprobá. 4. Al volver a la conversación, las herramientas de Tilopay quedan disponibles. No hay que pegar ningún token: el conector se registra solo. ## ChatGPT [#chatgpt] ChatGPT se conecta como conector remoto usando la misma URL. 1. Agregá el servidor como conector remoto con la URL de arriba. 2. La autorización se completa en el navegador con tus credenciales de Tilopay y el código de verificación. 3. Al aprobar, el conector queda activo y el modelo puede llamar las herramientas. ## GitHub Copilot y VS Code [#copilot] En VS Code (con Copilot en modo agente) se declara un servidor MCP remoto de tipo HTTP. 1. Declará el servidor con la URL, sin token ni credenciales en el archivo de configuración. 2. Al primer uso, el editor abre el navegador para autorizar. 3. Después de aprobar, las herramientas aparecen en la lista de herramientas del agente. ## Cursor y otros editores [#cursor] Cursor y editores equivalentes usan el mismo esquema: un servidor MCP remoto por HTTP. 1. Agregá el servidor remoto con la URL, sin token en la configuración. 2. Autorizá en el navegador cuando el editor lo pida. 3. Habilitá las herramientas para el chat o el agente del editor. ## Gemini [#gemini] Los clientes de Gemini que soportan MCP remoto se conectan igual: se registra la URL del servidor y la autorización ocurre en el navegador. Si el cliente sólo soporta servidores MCP locales por stdio, se requiere un puente que hable Streamable HTTP contra la URL de Tilopay. ## Otros clientes MCP [#otros] Para un cliente propio o cualquier otro agente, el requisito es soportar transporte **Streamable HTTP** y **OAuth 2.0 con registro dinámico de cliente**. La secuencia es: 1. El cliente llama al servidor y recibe un `401` con `WWW-Authenticate`, que apunta a `/.well-known/oauth-protected-resource`. 2. El cliente descubre los endpoints del proveedor de identidad. 3. Se registra dinámicamente y abre la pantalla de autorización. 4. El usuario inicia sesión y aprueba el consentimiento. 5. El cliente queda conectado con `authorization_code` y `refresh_token`. Lo único que se configura es la URL del servidor. ## Verificar la conexión [#verificar] Pedile al agente que liste las herramientas disponibles: deberían aparecer las de Tilopay, organizadas en los 14 grupos del [API de adquirencia](/developers/agentes/mcp/adquirencia) (lista completa). El grupo [API bancario (BaaS)](/developers/agentes/mcp/api-bancario) se activa bajo solicitud y sólo funciona para usuarios con credenciales del API bancario de Tilopay. Una primera prueba segura es una consulta de sólo lectura, por ejemplo pedir las transacciones de un rango de fechas. Para flujos completos mirá las [recetas](/developers/agentes/mcp/recetas). ## Fechas en UTC [#fechas-utc] En las consultas de ventas, `startDate` y `endDate` se envían en UTC con formato `YYYY-MM-DD HH:mm:ss`. Convertí el rango local antes de consultar: Costa Rica es UTC-6, por lo que el día local 2026-10-20 va de `2026-10-20 06:00:00` a `2026-10-21 05:59:59` UTC. Usá la misma conversión al comparar períodos. ## Si algo falla [#problemas] - **El cliente no abre la autorización**: revisá que el servidor esté declarado como remoto por HTTP y no como servidor local. - **La autorización no termina**: la sesión se inicia con el correo y la contraseña del panel de Tilopay; además hay que confirmar el código de verificación que llega al correo. - **El agente no ve herramientas**: en varios clientes hay que habilitarlas para la conversación o para el modo agente después de conectar. - **Una herramienta responde vacío**: puede ser el ambiente consultado; varias herramientas trabajan en `production` por defecto. --- # Qué puede hacer un agente > Alcance real de un agente conectado al servidor MCP: qué herramientas leen, qué herramientas modifican estado y qué controles existen. - kind: guide - status: stable - last_verified: 2026-10-20 - url: https://tilopay.com/developers/agentes/mcp/permisos ## Alcance de las herramientas [#alcance] De las 117 herramientas, 63 sólo leen y 54 modifican estado. 20 de esas 54 están marcadas como sensibles. Las marcadas como sensibles, agrupadas por tema. La lista sale del catálogo: son todas las herramientas con nivel de acceso sensible. Enviar mensajes (enlaces, comprobantes o avisos por WhatsApp o correo) cuenta como escritura, no como operación sensible. **Mueven dinero: reembolsos y capturas, cobros a tarjetas guardadas, transferencias bancarias, su confirmación y el doble control** - [`tilopay_modify_transaction`](https://tilopay.com/developers/agentes/mcp/ventas#tilopay-modify-transaction): Capturar, reembolsar o reversar - [`tilopay_charge_saved_card`](https://tilopay.com/developers/agentes/mcp/tarjetas-guardadas#tilopay-charge-saved-card): Cobrar a una tarjeta guardada de un cliente - [`tilopay_saved_cards_create_payments`](https://tilopay.com/developers/agentes/mcp/tarjetas-guardadas#tilopay-saved-cards-create-payments): Cobrar a tarjetas almacenadas - [`baas_send_transfer`](https://tilopay.com/developers/agentes/mcp/api-bancario/send-transfer#baas-send-transfer): Enviar transferencia BaaS - [`baas_confirm_transfer`](https://tilopay.com/developers/agentes/mcp/api-bancario/confirm-transfer#baas-confirm-transfer): Autorizar la transferencia pendiente - [`banca_decide_approval`](https://tilopay.com/developers/agentes/mcp/api-bancario/otras-operaciones#banca-decide-approval): Aprobar o rechazar una operación pendiente **Borran o desactivan: enlaces, productos, planes, cupones, contactos, tarjetas guardadas, recordatorios, tiendas, dominios y pedidos** - [`tilopay_delete_payment_link`](https://tilopay.com/developers/agentes/mcp/enlaces-de-pago#tilopay-delete-payment-link): Eliminar enlace de pago - [`tilopay_catalog_delete_item`](https://tilopay.com/developers/agentes/mcp/catalogo#tilopay-catalog-delete-item): Borrar un producto del catálogo - [`tilopay_delete_contact`](https://tilopay.com/developers/agentes/mcp/contactos#tilopay-delete-contact): Eliminar contacto - [`tilopay_store_delete`](https://tilopay.com/developers/agentes/mcp/microtienda#tilopay-store-delete): Desactivar una microtienda - [`tilopay_store_domain_remove`](https://tilopay.com/developers/agentes/mcp/microtienda#tilopay-store-domain-remove): Quitar un dominio propio - [`tilopay_orders_disable`](https://tilopay.com/developers/agentes/mcp/microtienda#tilopay-orders-disable): Apagar la gestión de pedidos - [`tilopay_cancel_reminder`](https://tilopay.com/developers/agentes/mcp/recordatorios#tilopay-cancel-reminder): Cancelar recordatorio - [`tilopay_recurring_delete_plan`](https://tilopay.com/developers/agentes/mcp/recurrentes#tilopay-recurring-delete-plan): Eliminar plan de suscripción - [`tilopay_recurring_delete_coupon`](https://tilopay.com/developers/agentes/mcp/recurrentes#tilopay-recurring-delete-coupon): Eliminar un cupón - [`tilopay_remove_saved_card`](https://tilopay.com/developers/agentes/mcp/tarjetas-guardadas#tilopay-remove-saved-card): Eliminar una tarjeta guardada de un cliente **Cambian el estado de un suscriptor y sus cobros futuros** - [`tilopay_recurring_manage_subscriber`](https://tilopay.com/developers/agentes/mcp/recurrentes#tilopay-recurring-manage-subscriber): Pausar, reactivar o eliminar un suscriptor - [`tilopay_recurring_edit_subscriber`](https://tilopay.com/developers/agentes/mcp/recurrentes#tilopay-recurring-edit-subscriber): Editar suscriptor de un plan **Cortan el acceso: desvincular la cuenta y quitar a un empleado** - [`tilopay_unlink_account`](https://tilopay.com/developers/agentes/mcp/cuenta#tilopay-unlink-account): Desvincular mi cuenta - [`tilopay_remove_employee`](https://tilopay.com/developers/agentes/mcp/cuenta#tilopay-remove-employee): Quitar acceso a un empleado ## Herencia de permisos [#herencia-de-permisos] El servidor usa las credenciales de API del comercio, así que hereda exactamente sus permisos: no impone barreras adicionales por herramienta. Un usuario activo puede reembolsar y hacer cobros masivos; esas operaciones exigen el código de confirmación que llega al correo (ver [Confirmaciones que exige Tilopay](#confirmaciones)). ## Controles que existen [#controles] - Un interruptor de activación por usuario, que corta el acceso sin borrar la cuenta. - Un rol de administrador separado, que sólo sirve para gestionar usuarios y credenciales. - Un límite de tasa de 60 llamadas por minuto por usuario. ## Confirmaciones que exige Tilopay [#confirmaciones] Tilopay exige confirmaciones en el servidor para las operaciones que se detallan a continuación. Para las demás herramientas de escritura, la confirmación humana corresponde al cliente MCP. **Código de 6 dígitos por correo (segundo factor).** Lo exigen `tilopay_modify_transaction`, `tilopay_charge_saved_card`, `tilopay_saved_cards_create_payments`, `tilopay_remove_saved_card`, `tilopay_delete_payment_link` y `tilopay_recurring_manage_subscriber`. El ciclo es: 1. Se llama la herramienta sin `confirmation_code`. 2. La respuesta trae `structuredContent` con `{requires_confirmation: true, channel: "email", expires_in_seconds: 600, summary, details[], risk_level, second_channel}` y Tilopay envía el código al correo del comercio. 3. Se repite la MISMA llamada con los mismos parámetros más `confirmation_code`. El código vence a los 10 minutos, admite 5 intentos, se pueden pedir 3 códigos cada 10 minutos y cada código nuevo invalida el anterior. Con riesgo elevado el mismo código llega también por SMS si hay número configurado. **Extensión de depósitos.** `tilopay_deposit_extend` exige un código de 6 dígitos por correo y es sólo para el dueño. Su esquema no declara `confirmation_code`, por lo que el flujo de dos llamadas se completa desde el Asistente de WhatsApp. **`confirm: true` obligatorio.** `tilopay_unlink_account`, `tilopay_remove_employee` y `baas_get_account_number` sólo se ejecutan con `confirm: true`. **Huella de lote.** `tilopay_recurring_settle_batch` devuelve un resumen con `fingerprint` y sólo ejecuta con `confirm: true` y la misma huella (máximo 20 enlaces). **Transferencias bancarias.** El código lo envía el portal Banca Cliente al correo y se pasa como `code` a `baas_confirm_transfer` (o a `banca_decide_approval` cuando hay doble control). ### Confirmación humana en el cliente MCP [#confirmacion-humana] Para el resto de herramientas de escritura, el cliente MCP debe pedir confirmación humana antes de ejecutarlas. > **Advertencia:** `tilopay_charge_saved_card` y `tilopay_saved_cards_create_payments` no deduplican: repetir la > operación con un código nuevo cobra otra vez. Antes de reintentar, verificá el resultado con > `tilopay_sales_summary` o `tilopay_saved_cards_list_collections`. `tilopay_catalog_delete_item` no exige código por correo: el Asistente de WhatsApp pide confirmación en el chat y los clientes MCP deben pedir confirmación humana. `tilopay_recurring_edit_subscriber` tampoco exige código por correo; para pausar, reactivar o eliminar con segundo factor existe `tilopay_recurring_manage_subscriber`. --- # Recetas > Catorce flujos de punta a punta con el servidor MCP: dashboard de insights, ventas por WhatsApp, recuperación de cobros recurrentes fallidos, cobranza B2B, proyección de caja con datos bancarios, detección de anomalías, cierre de mes, reembolsos, suscripciones recurrentes, optimización de planes, cobros a tarjetas almacenadas, pausa o baja de suscriptores, depuración de integraciones y Tilopay como herramienta de otros agentes. - kind: guide - status: stable - last_verified: 2026-10-20 - url: https://tilopay.com/developers/agentes/mcp/recetas ## Construir un dashboard de insights en tiempo real [#dashboard-insights] 1. `tilopay_sales_summary` trae los totales, costos y neto del período que querés monitorear. 2. `tilopay_analyze_sales` convierte esos números en un resumen narrativo con tendencias y observaciones. 3. `tilopay_list_transactions` lista las transacciones recientes para completar el tablero. 4. `tilopay_get_transaction` abre el detalle de cualquier operación que necesite revisión. > **Advertencia:** El resumen usa UTC, no hora local. Si tenés poco volumen, las tendencias y los > clientes destacados pueden venir vacíos. ### Ejemplos de preguntas para el dashboard [#ejemplos-dashboard] - “¿Cómo me fue hoy?” → `tilopay_sales_summary` + `tilopay_analyze_sales`. - “¿Cuáles son mis productos o servicios más vendidos esta semana?” → `tilopay_analyze_sales` sobre el rango de los últimos 7 días. - “¿Tengo transacciones fallidas o sin liquidar?” → `tilopay_list_transactions` filtrando por estado, luego `tilopay_get_transaction` para cada caso. - “¿Cómo evolucionan mis ingresos netos respecto al mes pasado?” → comparar dos llamadas a `tilopay_sales_summary` con ventanas de fechas distintas. ## Vender por WhatsApp desde el catálogo [#cobrar-por-whatsapp] 1. `tilopay_catalog_list_items` lista los productos o servicios del comercio para responder la consulta del cliente con nombres y precios reales. 2. `tilopay_catalog_get_item` abre el detalle del ítem elegido cuando hay que confirmar precio, moneda o descripción antes de armar el pedido. 3. El agente arma el pedido, calcula el total y se lo confirma al cliente antes de cobrar. 4. `tilopay_save_contact` guarda al comprador (nombre, correo, teléfono) para asociarlo al cobro y reutilizarlo en ventas futuras. 5. `tilopay_create_charge` crea el enlace por el total del pedido, con una descripción que identifique la orden. 6. `tilopay_send_payment_link_whatsapp` prepara el envío al cliente. 7. `tilopay_get_payment_link` consulta el estado del enlace para confirmar el pago y cerrar la conversación con el comprobante. `tilopay_send_payment_link_whatsapp` no envía el mensaje: devuelve un enlace `wa.me` con el texto listo para enviar con un toque. Si no hay teléfono ni contacto guardado con ese nombre, la herramienta lo pide. El agente puede quedarse consultando `tilopay_get_payment_link` cada cierto tiempo para avisarle al comercio en cuanto el enlace pase a pagado. > **Nota:** Con esta receta un comercio sin tienda en línea vende de punta a punta dentro del chat: catálogo, > pedido, cobro y confirmación, sin intervención humana salvo la que el propio comercio quiera > exigir. ## Recuperar cobros recurrentes fallidos (dunning inteligente) [#dunning-inteligente] 1. `tilopay_recurring_list_plans` lista los planes activos del comercio. 2. `tilopay_recurring_subscriber_payments` recorre los pagos de los suscriptores de cada plan y separa los cobros rechazados del período. 3. `tilopay_get_transaction` abre cada rechazo para leer el código de respuesta y clasificar la causa: fondos insuficientes, tarjeta vencida, tarjeta bloqueada, sospecha de fraude. 4. Según la causa, el agente decide la acción y se la propone al comercio: esperar el reintento del plan cuando el rechazo es transitorio (fondos insuficientes), o pedirle al cliente un nuevo medio de pago cuando el rechazo es definitivo (tarjeta vencida o bloqueada). 5. `tilopay_create_charge` crea un enlace por el saldo por cobrar cuando hay que pedirle al cliente que pague la cuota con otra tarjeta. 6. `tilopay_send_payment_link_whatsapp` o `tilopay_send_payment_link_email` prepara el mensaje al cliente con un texto adaptado al motivo del rechazo. 7. `tilopay_get_payment_link` confirma cuando el cliente pagó, y `tilopay_recurring_get_subscriber` verifica el estado del suscriptor después de la recuperación. Un agente que corre esta receta cada mañana convierte la lista de rechazos en dos colas: la que se resuelve sola con el reintento del plan y la que necesita un mensaje al cliente. El comercio recibe solo el resumen: cuántos cobros se recuperaron y cuáles siguen sin recuperarse. > **Advertencia:** No uses `tilopay_recurring_manage_subscriber` para "castigar" un rechazo: `pause` y `delete` > afectan cobros futuros y `delete` no se deshace. Pausar o dar de baja a un suscriptor es una > decisión del comercio, con confirmación humana explícita, nunca una reacción automática a un cobro > fallido. ## Cobranza B2B con cuentas por cobrar [#cobranza-b2b] 1. `tilopay_list_contacts` trae los clientes empresariales del comercio; `tilopay_save_contact` registra los que falten con nombre, correo y teléfono de la persona que paga. 2. `tilopay_create_charge` crea un enlace por cada factura sin pagar, con el número de factura en la descripción. 3. `tilopay_send_payment_link_email` prepara el primer envío; `tilopay_send_payment_link_whatsapp` prepara el recordatorio cuando la factura sigue sin pagar. 4. `tilopay_get_payment_link` revisa el estado de cada enlace para actualizar la lista de cuentas por cobrar sin entrar al panel. 5. `baas_search_payment` o `baas_list_payments` buscan en las cuentas bancarias del comercio una transferencia directa (SINPE o transferencia bancaria) que coincida con el monto y el cliente, para marcar como pagada una factura que el cliente liquidó fuera del enlace. 6. `tilopay_delete_payment_link` elimina el enlace de una factura que ya se pagó por transferencia, para evitar un cobro doble. Esta receta responde el "¿ya me pagaron?" que consume horas administrativas en negocios que facturan a empresas: una sola lista con facturas, enlaces, estado y pagos recibidos por cualquier vía. > **Nota:** Esta receta usa sólo herramientas `baas_*` de lectura. `baas_send_transfer` existe, pero exige el > código que llega al correo y no forma parte de esta receta. Las herramientas `baas_*` requieren > que Tilopay haya registrado las credenciales del API bancario del comercio; si no están > configuradas, la herramienta lo indica y la receta sigue funcionando solo con los enlaces de pago. ## Proyectar la caja con datos de la pasarela y del banco (CFO de bolsillo) [#cfo-de-bolsillo] 1. `tilopay_sales_summary` trae las ventas de las últimas semanas para estimar los ingresos esperados del período siguiente. 2. `tilopay_recurring_list_plans` y `tilopay_recurring_get_plan` cuantifican los cobros recurrentes comprometidos y sus fechas. 3. `baas_list_balances` o `baas_get_balance` traen el saldo real de cada cuenta bancaria del comercio. 4. `baas_list_payments` lista las transferencias de los últimos meses para detectar las salidas recurrentes: planilla, alquiler, proveedores. 5. `baas_analyze_payments` resume esos movimientos en lenguaje natural para identificar patrones y fechas pico. 6. El agente combina saldo, entradas previstas y salidas previstas en una proyección diaria, señala los días con saldo mínimo o negativo y propone acciones. 7. `tilopay_create_charge` y `tilopay_send_payment_link_email` ponen a cobro facturas sin pagar cuando el comercio aprueba esa acción. El valor está en cruzar dos fuentes que normalmente viven separadas: la pasarela sabe qué va a entrar y el banco sabe qué hay y qué sale. Una rutina semanal produce un briefing corto con la proyección y las alertas, antes de que abra el negocio. > **Advertencia:** Esta receta usa sólo herramientas `baas_*` de lectura. `baas_send_transfer` existe, pero exige el > código que llega al correo y no forma parte de esta receta. Si la proyección sugiere mover fondos > entre cuentas, esa acción la ejecuta una persona con la confirmación del banco; el agente solo la > recomienda y la registra. La proyección es una estimación, no un estado financiero. ## Detectar anomalías y actuar [#detector-anomalias] 1. `tilopay_sales_summary` compara la ventana actual (por ejemplo la última hora o el día) contra el mismo período de referencia para detectar caídas de aprobación, picos de rechazos o cambios bruscos en el ticket promedio. 2. `tilopay_list_transactions` filtra por estado para ver si los rechazos se concentran en un método de pago, una moneda o un patrón de intentos repetidos. 3. `tilopay_get_transaction` abre casos representativos para leer los códigos de respuesta. 4. `tilopay_diagnostics` verifica credenciales y disponibilidad de los endpoints para separar un problema de la integración del comercio de un problema de los clientes o del emisor. 5. `tilopay_help_guides` busca en las guías oficiales la explicación y los pasos de corrección que correspondan al código de respuesta o al síntoma. 6. El agente abre la alerta con el diagnóstico ya hecho: qué cambió, desde cuándo, causa probable y acción sugerida. > **Advertencia:** El resumen de ventas usa UTC. Al comparar ventanas cortas, alineá las horas; una "caída" a > medianoche local puede ser solo el corte del día en UTC. Muchos intentos rechazados en pocos > minutos con montos pequeños y tarjetas distintas pueden indicar pruebas de tarjetas robadas: > reportalo a soporte en vez de reintentar. ## Cerrar las ventas del mes [#cierre-de-mes] 1. `tilopay_sales_summary` devuelve los totales, costos y neto del período. 2. `tilopay_analyze_sales` produce el informe en lenguaje natural. 3. `tilopay_get_transaction` trae el detalle de las transacciones que haya que revisar. > **Advertencia:** Las horas y los días del resumen están en UTC, no en hora local. Las tendencias y los clientes > destacados vienen vacíos si la muestra es chica. ## Reembolsar con confirmación humana [#reembolso] 1. `tilopay_list_transactions` localiza la transacción en el rango de fechas. 2. `tilopay_get_transaction` muestra el detalle para confirmar que es la correcta. 3. El agente le pide confirmación al usuario. Este paso lo impone el cliente MCP, no Tilopay. 4. `tilopay_modify_transaction` ejecuta la modificación con la acción y el monto. ## Revisar una suscripción recurrente [#suscripcion-recurrente] 1. `tilopay_recurring_list_plans` lista los planes de cobro recurrente del comercio. 2. `tilopay_recurring_get_plan` abre el plan que interesa por su ID. 3. `tilopay_recurring_get_subscriber` muestra el detalle del suscriptor. 4. `tilopay_recurring_subscriber_payments` lista los pagos de ese suscriptor para ver cuáles pasaron y cuáles no. Sirve para responder "¿por qué este cliente aparece sin cobrar este mes?" sin entrar al panel. ## Optimizar los planes de suscripción [#optimizar-planes] 1. `tilopay_recurring_list_plans` lista los planes activos con su precio y periodicidad. 2. `tilopay_recurring_get_plan` abre cada plan para conocer la cantidad de suscriptores y su configuración. 3. `tilopay_recurring_subscriber_payments` recorre los pagos por suscriptor para calcular, por plan, la tasa de cobros exitosos, el mes en que más suscriptores dejan de pagar y la antigüedad promedio. 4. `tilopay_recurring_get_subscriber` revisa los casos atípicos que el análisis señale. 5. El agente presenta el comparativo entre planes: retención, ingreso por suscriptor y punto de abandono, y propone cambios de precio, periodicidad o contenido. 6. `tilopay_create_charge` permite probar una oferta nueva con un segmento pequeño de contactos antes de modificar un plan. Es análisis de precios con datos reales de cobro. El agente no modifica planes: propone, y el comercio decide en el panel. ## Pausar o dar de baja a un suscriptor [#pausar-suscriptor] 1. `tilopay_recurring_get_subscriber` confirma que el suscriptor es el correcto. 2. El agente le pide confirmación al usuario, con el nombre y el plan a la vista. 3. `tilopay_recurring_manage_subscriber` ejecuta `pause`, `reactivate` o `delete`. > **Advertencia:** `tilopay_recurring_manage_subscriber` está marcada como sensible: afecta cobros futuros y `delete` > no se deshace. Nunca la ejecutés sin confirmación humana explícita. ## Cobrar a un grupo con tarjetas almacenadas [#cobro-masivo] 1. `tilopay_saved_cards_list_groups` lista los grupos de cobro. 2. `tilopay_saved_cards_list_affiliates` muestra los afiliados del grupo elegido, para saber a cuántas tarjetas se le va a cobrar. 3. El agente resume monto, moneda, motivo y cantidad de afiliados, y pide confirmación. 4. `tilopay_saved_cards_create_payments` crea los cobros. 5. `tilopay_saved_cards_list_collections` y `tilopay_saved_cards_collection_detail` revisan el resultado: la segunda necesita el `code` que devuelve la primera. > **Advertencia:** `tilopay_saved_cards_create_payments` mueve dinero real de las tarjetas almacenadas. Tratala como > una operación de un solo intento: confirmá antes, y verificá después con el detalle del cobro. ## Depurar una integración y acompañar a un desarrollador [#depurar-integracion] 1. `tilopay_diagnostics` prueba las credenciales y un endpoint de cada grupo del API, para separar un problema de credenciales de un problema de la petición. 2. `tilopay_debug_code` recibe el fragmento de código, el log o el stack trace y devuelve diagnóstico, causa raíz, corrección y riesgos. 3. `tilopay_help_guides` responde las dudas de uso del panel con las guías oficiales. 4. `tilopay_list_transactions` y `tilopay_get_transaction` confirman si la operación que el desarrollador cree fallida en realidad llegó a Tilopay y con qué resultado. `tilopay_debug_code` no lee el repositorio ni ejecuta el código: analiza sólo lo que le pasás. Antes de mandarlo, quitá credenciales del fragmento; la herramienta oculta lo que reconoce como secreto, pero no reemplaza esa revisión. Con estas cuatro herramientas un agente de soporte atiende el onboarding técnico completo: verifica la cuenta, encuentra la causa del error, entrega la corrección con la guía oficial y confirma contra las transacciones reales. Las preguntas que se repiten son la señal de qué guía o ejemplo debe agregarse al portal. > **Nota:** Las tarjetas de prueba del modo sandbox están en la guía de pruebas del portal. El modo sandbox se > alterna desde la cuenta; no existe un host separado. ## Tilopay como herramienta de otros agentes [#tilopay-como-herramienta] 1. El acceso es autoservicio: agregás el servidor MCP en tu cliente con la URL `https://mcp.tilopay.com/mcp` y autorizás la sesión con el correo y la contraseña de tu cuenta de Tilopay, más el código de verificación que te enviamos. No hay formulario ni aprobación previa. 2. El agente externo (el asistente de un ERP, un bot de tienda en línea, un agente contable) conecta el servidor MCP con esa sesión OAuth y ejecuta `tilopay_diagnostics` para verificar la conexión. 3. Con el catálogo de herramientas cargado, el agente externo usa las herramientas de consulta (`tilopay_sales_summary`, `tilopay_list_transactions`, `tilopay_recurring_*`, `baas_*`) para responder preguntas del negocio dentro de su propia conversación. 4. Para acciones que crean o mueven dinero (`tilopay_create_charge`, `tilopay_modify_transaction`, `tilopay_saved_cards_create_payments`, `tilopay_recurring_manage_subscriber`) el agente externo aplica la política de confirmación descrita en la página de permisos antes de ejecutar. Esta receta cambia la posición del MCP: no es solo un asistente dentro de Tilopay, es la capa de pagos que cualquier agente puede invocar. Las demás recetas de esta página funcionan igual cuando las ejecuta un agente de terceros. > **Advertencia:** El consumo del MCP puede tener costos adicionales según el volumen; Tilopay se los comunica al > comercio. Las herramientas marcadas como sensibles exigen > confirmación humana en el cliente MCP que las ejecute, sea de Tilopay o de un tercero. ¿Querés dejar estas recetas empaquetadas y repetibles? [Instalá una skill](/developers/agentes/mcp/skills). --- # Skills para agentes > Paquetes de instrucciones listos para que un agente use el MCP de Tilopay en tareas concretas, como el cierre de caja, cobrar por WhatsApp o recuperar pagos rechazados. - kind: guide - status: stable - last_verified: 2026-10-20 - url: https://tilopay.com/developers/agentes/mcp/skills ## Qué es una skill [#que-es] Una skill es un paquete de instrucciones (un `SKILL.md` más sus referencias) que el agente carga sólo cuando el comercio le pide algo de ese tema. No requiere código ni credenciales: usa el MCP de Tilopay que ya está conectado, y las instrucciones le dicen qué herramientas llamar, en qué orden y cómo validar los números antes de responder. La diferencia con las [recetas](/developers/agentes/mcp/recetas) es que la receta es el ejemplo de prompt; la skill lo deja empaquetado y repetible, con reglas de cálculo y de seguridad. ## Antes de empezar [#antes] Necesitás una cuenta de Tilopay. Si instalás el plugin (opción 2 de abajo), el conector del MCP viene incluido y solo tenés que autorizarlo con tu cuenta la primera vez. Para las demás opciones, primero [conectá el MCP en tu cliente](/developers/agentes/mcp/conectar). Las skills no piden ni guardan credenciales. ## Skills disponibles [#skills] ### Todas las skills en un plugin Las seis skills y el conector del MCP de Tilopay en un solo plugin para Cowork, el chat de claude.ai y Claude Code. Instalalo desde el marketplace de Tilopay con los comandos de abajo. ```text /plugin marketplace add tilopay/claude-plugins /plugin install tilopay-mcp-skills@tilopay ``` - [Ver en GitHub](https://github.com/tilopay/claude-plugins) - Versión: 1.0.1 - Copiar prompt para Claude Code: «Lee el índice de skills de Tilopay en https://tilopay.com/developers/skills/index.md. Para cada skill, crea una carpeta con su nombre dentro de ~/.claude/skills/, guarda ahí su SKILL.md y, si el índice lista archivos de referencia, guárdalos en una subcarpeta references/ con el mismo nombre de archivo. Al final dime qué skills quedaron instaladas.» ### cierre-de-caja Cierre de caja del día, la semana o el mes por moneda: aprobadas, rechazadas, reembolsos, desglose exacto de comisiones y retenciones, neto a liquidar y próximo depósito, con validación de que los números cuadran contra el balance oficial de Tilopay. - Prompt de ejemplo: «Dame el cierre de caja de hoy» - Herramientas del MCP: `tilopay_list_transactions`, `tilopay_sales_summary`, `tilopay_settlement_balance`, `tilopay_settlements_list`, `tilopay_switch_commerce` - Grupos: [Ventas y transacciones](https://tilopay.com/developers/agentes/mcp/ventas) - Versión: 1.0.1 - [SKILL.md](https://tilopay.com/developers/skills/cierre-de-caja/SKILL.md) - Prompt para usarla sin instalar: «Lee https://tilopay.com/developers/skills/cierre-de-caja/SKILL.md y los archivos que referencia, y sigue esas instrucciones usando mi conector de Tilopay. Dame el cierre de caja de hoy» ### cobrar-por-whatsapp Convierte una frase en un cobro real y en el mensaje de WhatsApp listo para enviar; genera el QR si se pide y verifica después si el cliente ya pagó. - Prompt de ejemplo: «Cóbrale 25 mil colones a Ana por el curso de fotografía» - Herramientas del MCP: `tilopay_create_charge`, `tilopay_send_payment_link_whatsapp`, `tilopay_send_payment_link_email`, `tilopay_payment_link_qr`, `tilopay_list_receipts`, `tilopay_find_payment`, `tilopay_list_contacts` - Grupos: [Enlaces de pago](https://tilopay.com/developers/agentes/mcp/enlaces-de-pago), [Comprobantes de cobro](https://tilopay.com/developers/agentes/mcp/comprobantes), [Contactos](https://tilopay.com/developers/agentes/mcp/contactos) - Versión: 1.0.1 - [SKILL.md](https://tilopay.com/developers/skills/cobrar-por-whatsapp/SKILL.md) - Prompt para usarla sin instalar: «Lee https://tilopay.com/developers/skills/cobrar-por-whatsapp/SKILL.md y los archivos que referencia, y sigue esas instrucciones usando mi conector de Tilopay. Cóbrale 25 mil colones a Ana por el curso de fotografía» ### rechazos-y-recuperacion Analiza los pagos rechazados, los agrupa por motivo con las etiquetas de la guía oficial «Motivos de rechazo», detecta patrones (mismo cliente reintentando, misma orden recuperada después, canal, horario) y propone acciones concretas, incluido el mensaje al cliente y un enlace nuevo. - Prompt de ejemplo: «¿Por qué me rechazaron pagos este mes y cuáles puedo recuperar?» - Herramientas del MCP: `tilopay_list_transactions`, `tilopay_sales_summary`, `tilopay_create_charge`, `tilopay_send_payment_link_whatsapp`, `tilopay_help_guides` - Grupos: [Ventas y transacciones](https://tilopay.com/developers/agentes/mcp/ventas), [Enlaces de pago](https://tilopay.com/developers/agentes/mcp/enlaces-de-pago), [Soporte y diagnóstico](https://tilopay.com/developers/agentes/mcp/soporte) - Versión: 1.0.1 - [SKILL.md](https://tilopay.com/developers/skills/rechazos-y-recuperacion/SKILL.md) - Prompt para usarla sin instalar: «Lee https://tilopay.com/developers/skills/rechazos-y-recuperacion/SKILL.md y los archivos que referencia, y sigue esas instrucciones usando mi conector de Tilopay. ¿Por qué me rechazaron pagos este mes y cuáles puedo recuperar?» - [Guía «Motivos de rechazo»](https://tilopay.com/guias/panel-transacciones/motivos-de-rechazo) ### conciliacion-mensual Conciliación contable de un mes, quincena o rango: cruza ventas aprobadas, reembolsos y liquidaciones depositadas, con los seis campos de costo etiquetados, y entrega un CSV o Excel para el contador más un resumen de diferencias. - Prompt de ejemplo: «Concíliame septiembre para el contador» - Herramientas del MCP: `tilopay_list_transactions`, `tilopay_refunds_list`, `tilopay_settlements_list`, `tilopay_settlement_transactions`, `tilopay_settlement_balance`, `tilopay_billing_list`, `tilopay_switch_commerce` - Grupos: [Ventas y transacciones](https://tilopay.com/developers/agentes/mcp/ventas), [Liquidaciones, depósitos y facturación](https://tilopay.com/developers/agentes/mcp/liquidaciones), [Cuenta, comercio y equipo](https://tilopay.com/developers/agentes/mcp/cuenta) - Versión: 1.0.0 - [SKILL.md](https://tilopay.com/developers/skills/conciliacion-mensual/SKILL.md) - Prompt para usarla sin instalar: «Lee https://tilopay.com/developers/skills/conciliacion-mensual/SKILL.md y los archivos que referencia, y sigue esas instrucciones usando mi conector de Tilopay. Concíliame septiembre para el contador» ### cfo-de-bolsillo Análisis financiero de ventas: compara períodos del mismo largo, ticket promedio, mejores días y horas, concentración de clientes, costo efectivo de Tilopay como porcentaje de la venta y una proyección simple de cierre de mes y flujo con el próximo depósito, siempre etiquetada como estimación. - Prompt de ejemplo: «¿Cómo voy este mes comparado con el anterior?» - Herramientas del MCP: `tilopay_list_transactions`, `tilopay_sales_summary`, `tilopay_settlement_balance`, `tilopay_settlements_list`, `tilopay_get_business_profile` - Grupos: [Ventas y transacciones](https://tilopay.com/developers/agentes/mcp/ventas), [Liquidaciones, depósitos y facturación](https://tilopay.com/developers/agentes/mcp/liquidaciones), [Perfil del negocio y recetas](https://tilopay.com/developers/agentes/mcp/perfil) - Versión: 1.0.0 - [SKILL.md](https://tilopay.com/developers/skills/cfo-de-bolsillo/SKILL.md) - Prompt para usarla sin instalar: «Lee https://tilopay.com/developers/skills/cfo-de-bolsillo/SKILL.md y los archivos que referencia, y sigue esas instrucciones usando mi conector de Tilopay. ¿Cómo voy este mes comparado con el anterior?» ### catalogo-y-cobros-fijos Gestiona el catálogo de productos y servicios: busca productos con su enlace de pago, crea o edita desde una frase o una lista, entrega el QR de un producto o el QR permanente de mostrador, y conecta el catálogo a Facebook/Instagram, Google Shopping, TikTok o Pinterest. - Prompt de ejemplo: «Agregá al catálogo Clase de yoga a 8 mil colones» - Herramientas del MCP: `tilopay_catalog_list_items`, `tilopay_catalog_get_item`, `tilopay_catalog_create_item`, `tilopay_catalog_update_item`, `tilopay_catalog_delete_item`, `tilopay_payment_link_qr`, `tilopay_static_payment_qr`, `tilopay_catalog_feed`, `tilopay_store_list`, `tilopay_send_payment_link_whatsapp` - Grupos: [Catálogo de productos](https://tilopay.com/developers/agentes/mcp/catalogo), [Enlaces de pago](https://tilopay.com/developers/agentes/mcp/enlaces-de-pago), [Microtienda y pedidos](https://tilopay.com/developers/agentes/mcp/microtienda) - Versión: 1.0.0 - [SKILL.md](https://tilopay.com/developers/skills/catalogo-y-cobros-fijos/SKILL.md) - Prompt para usarla sin instalar: «Lee https://tilopay.com/developers/skills/catalogo-y-cobros-fijos/SKILL.md y los archivos que referencia, y sigue esas instrucciones usando mi conector de Tilopay. Agregá al catálogo Clase de yoga a 8 mil colones» ## Cómo instalar [#instalar] **Opción 1 · Usarla ahora mismo, sin instalar nada (Claude, ChatGPT u otro asistente con el MCP conectado).** 1. Abrí una conversación nueva con el MCP de Tilopay conectado. 2. En la tarjeta de la skill, tocá «Copiar prompt». 3. Pegalo y enviá. El asistente lee las instrucciones desde tilopay.com y las aplica en esa conversación. La próxima vez, volvé a pegar el prompt (o usá la opción 2 para dejarla fija). Por ejemplo, el prompt del cierre de caja: ```text Lee https://tilopay.com/developers/skills/cierre-de-caja/SKILL.md y los archivos que referencia, y sigue esas instrucciones usando mi conector de Tilopay. Dame el cierre de caja de hoy ``` **Opción 2 · Instalar las seis de una vez en Claude (recomendada).** Tilopay publica sus skills como un plugin en GitHub. Se agrega una sola vez y queda guardado en tu cuenta: sirve en Cowork, en el chat de claude.ai y en Claude Code. El plugin incluye el conector del MCP de Tilopay: la primera vez que lo uses, Claude te pide autorizarlo con tu cuenta de Tilopay (en Cowork, desde la pestaña Connectors del plugin). En la app de Claude (Cowork): 1. Abrí la pestaña Cowork y luego Customize en la barra lateral. 2. Entrá a Plugins y hacé clic en Add → Add marketplace → Add from a repository. 3. Escribí `tilopay/claude-plugins` y confirmá. 4. Volvé a Discover, elegí tilopay-mcp-skills y hacé clic en Install. En Claude Code (terminal), dos comandos: ```text /plugin marketplace add tilopay/claude-plugins /plugin install tilopay-mcp-skills@tilopay ``` Desde ese momento, cuando pidas algo del tema («dame el cierre de caja de hoy») con el MCP de Tilopay conectado, Claude carga la skill sola. Para recibir mejoras, en el marketplace usá Check for updates o activá Sync automatically (en Claude Code: `/plugin marketplace update tilopay`).

Los plugins están disponibles en los planes de pago de Claude. Si tu organización limita qué marketplaces se pueden agregar, un Owner debe permitir tilopay/claude-plugins o sincronizarlo para todos desde la configuración de la organización.

**Opción 3 · Dejar una skill fija en un Proyecto de Claude.** La forma más simple sin instalar nada: creá un Proyecto en Claude, abrí el `SKILL.md` de la skill (enlace de la tarjeta), copiá todo el contenido y pegalo en las instrucciones del proyecto. Para que el asistente la use en cualquier conversación, pegá el prompt de la opción 1 cuando lo necesites. **Opción 4 · A mano en Claude Code (sin marketplace).** Pegá este prompt en Claude Code: ```text Lee el índice de skills de Tilopay en https://tilopay.com/developers/skills/index.md. Para cada skill, crea una carpeta con su nombre dentro de ~/.claude/skills/, guarda ahí su SKILL.md y, si el índice lista archivos de referencia, guárdalos en una subcarpeta references/ con el mismo nombre de archivo. Al final dime qué skills quedaron instaladas. ``` El prompt le pide a Claude Code crear una carpeta por skill dentro de `~/.claude/skills/` (o en `.claude/skills/` del proyecto para compartirla con tu equipo), guardando el `SKILL.md` publicado de cada una y, si tiene archivos de referencia, también esos archivos en una subcarpeta `references/`. **Otros clientes MCP.** Usá el `SKILL.md` como instrucciones del sistema o del proyecto, o pegá el prompt de la opción 1. ## Cómo funciona por dentro [#como-funciona] Con el cierre de caja como ejemplo, la secuencia es: 1. El agente convierte "hoy" a la hora local del comercio. 2. Llama `tilopay_list_transactions` con ese rango expresado en UTC. 3. Clasifica cada fila sólo por `code`: `1` es aprobada y `1101` es reembolso. 4. Suma los seis campos de costo con su nombre exacto: `commission`, `iva_commission`, `rent`, `retention_iva`, `cost` e `iva_tilopay`. 5. Valida que bruto − deducciones = neto y lo cruza con `tilopay_settlement_balance` antes de responder. > **Advertencia:** Las skills nunca llaman herramientas que muevan dinero sin confirmación del comercio. ## Crear tu propia skill [#crear] La estructura mínima de un `SKILL.md` es un frontmatter con `name` y `description`, seguido del procedimiento: ```markdown --- name: mi-skill description: Qué hace la skill y cuándo debe usarla el agente. --- 1. Paso del procedimiento, con la herramienta exacta que se llama. 2. Regla de validación antes de responder. ``` Tres consejos: 1. Nombrá las herramientas exactas que el agente tiene que llamar. 2. Poné las reglas de validación de los números. 3. Decí qué NO hacer. Para conocer todas las herramientas disponibles, consultá el manifiesto [`/developers/mcp.json`](/developers/mcp.json). Si armaste una skill útil para otros comercios, enviala a [soporte@tilopay.com](mailto:soporte@tilopay.com). --- # Herramientas de adquirencia > Resumen de los grupos de herramientas del MCP sobre el API de adquirencia: ventas y transacciones, enlaces de pago, catálogo de productos, contactos, perfil del negocio y recetas, microtienda y pedidos, avisos y notificaciones, comprobantes de cobro, recordatorios, cobros recurrentes, tarjetas guardadas y cobros masivos, liquidaciones, depósitos y facturación, cuenta, comercio y equipo, y soporte y diagnóstico. - kind: mcp-index - status: stable - last_verified: 2026-10-20 - url: https://tilopay.com/developers/agentes/mcp/adquirencia ## Qué cubre [#que-cubre] Estas son las herramientas que trabajan sobre el **API de adquirencia** de Tilopay: cobros con tarjeta, enlaces de pago y los datos que los rodean. Vienen activadas con el acceso MCP estándar, sin solicitud adicional, y operan siempre sobre el comercio asociado al usuario del MCP. Las herramientas del [API bancario](/developers/agentes/mcp/api-bancario) son un caso aparte: se activan bajo solicitud y exigen credenciales del API bancario. ## Grupos [#grupos] - [Ventas y transacciones](https://tilopay.com/developers/agentes/mcp/ventas) — 8 herramientas: Consulta de transacciones, métricas de ventas y la modificación de una transacción (captura, reembolso o reversión). - [Enlaces de pago](https://tilopay.com/developers/agentes/mcp/enlaces-de-pago) — 7 herramientas: Creación, consulta y borrado de enlaces de pago, más la preparación del envío por WhatsApp o correo. - [Catálogo de productos](https://tilopay.com/developers/agentes/mcp/catalogo) — 6 herramientas: Catálogo de productos y servicios del comercio: consulta, creación y edición de ítems (sin cambiar su enlace de pago), el feed para canales externos y el borrado de ítems. Incluye operaciones sensibles. - [Contactos](https://tilopay.com/developers/agentes/mcp/contactos) — 3 herramientas: Agenda del comercio: contactos guardados para reutilizar teléfono y correo al enviar un enlace de pago. - [Perfil del negocio y recetas](https://tilopay.com/developers/agentes/mcp/perfil) — 3 herramientas: Perfil del negocio del comercio (a qué se dedica, qué vende, cómo cobra y qué quiere mejorar) y las recetas de automatización que el agente sugiere a partir de ese perfil. - [Microtienda y pedidos](https://tilopay.com/developers/agentes/mcp/microtienda) — 13 herramientas: Microtiendas con carrito armadas desde el catálogo, y la gestión de los pedidos que entran por ahí: activación, resumen, listado, pendientes de entrega y cierre. - [Avisos y notificaciones](https://tilopay.com/developers/agentes/mcp/avisos) — 2 herramientas: Avisos por WhatsApp del comercio: cobros aprobados y rechazados, resumen diario y pedidos. Sólo lee y cambia la configuración; no envía mensajes por su cuenta. - [Comprobantes de cobro](https://tilopay.com/developers/agentes/mcp/comprobantes) — 2 herramientas: Comprobantes de los cobros aprobados: listarlos y reenviarle a un cliente el comprobante de su pago. - [Recordatorios](https://tilopay.com/developers/agentes/mcp/recordatorios) — 3 herramientas: Recordatorios por WhatsApp, de una vez o recurrentes, que pueden ejecutar una acción del agente al enviarse (resumen de ventas, enlaces pendientes, saldos). - [Cobros recurrentes](https://tilopay.com/developers/agentes/mcp/recurrentes) — 23 herramientas: Cobros recurrentes de punta a punta: crear, editar y borrar planes, cupones y suscriptores, enlaces de suscripción, cobros fallidos, la puesta al día por lotes (con huella de confirmación) y el paso a paso guiado para armar un plan. Incluye operaciones sensibles. - [Tarjetas guardadas y cobros masivos](https://tilopay.com/developers/agentes/mcp/tarjetas-guardadas) — 10 herramientas: Tarjetas guardadas de los clientes y cobros masivos: tokenización, métodos de pago disponibles, cobro a una tarjeta guardada, eliminación de una tarjeta y grupos de cobro. - [Liquidaciones, depósitos y facturación](https://tilopay.com/developers/agentes/mcp/liquidaciones) — 7 herramientas: - [Cuenta, comercio y equipo](https://tilopay.com/developers/agentes/mcp/cuenta) — 8 herramientas: - [Soporte y diagnóstico](https://tilopay.com/developers/agentes/mcp/soporte) — 3 herramientas: Respuestas tomadas de las guías oficiales y una prueba de conexión contra cada grupo del API. El nivel de acceso de cada herramienta y el detalle de sus parámetros está en la página de su grupo; el resumen de permisos está en [Permisos](/developers/agentes/mcp/permisos). --- # Ventas y transacciones > Herramientas del MCP para consultar transacciones, medir ventas y modificar una transacción. - kind: mcp-tool - status: stable - access: destructive - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/mcp/ventas ## Qué cubre [#que-cubre] Este grupo cubre la lectura de transacciones y el análisis de tus ventas, más la modificación de una transacción: captura, reembolso o reversión. La modificación mueve dinero real y está marcada como sensible. ## Herramientas [#herramientas] ### Resumen y tendencias de ventas [#tilopay-sales-summary] - `tilopay_sales_summary` - Acceso: Sólo lectura - Operación del API: `POST /api/v1/consultTransactions (y cálculo local)` — https://tilopay.com/developers/api/procesos-operativos/consult-transactions Calcula métricas de ventas a partir de las transacciones de Tilopay: totales por moneda, ticket promedio, tasa de aprobación, ventas por día, día de la semana y hora, mejores clientes, motivos de rechazo y tendencia. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `startDate` | string | sí | Fecha inicial "YYYY-MM-DD HH:mm:ss". Fechas en UTC (formato YYYY-MM-DD HH:mm:ss). Costa Rica es UTC-6: el día local 2026-10-20 va de 2026-10-20 06:00:00 a 2026-10-21 05:59:59. La distribución por hora/día del resultado viene en hora local del comercio. | | `endDate` | string | sí | Fecha final "YYYY-MM-DD HH:mm:ss". Fechas en UTC (formato YYYY-MM-DD HH:mm:ss). Costa Rica es UTC-6: el día local 2026-10-20 va de 2026-10-20 06:00:00 a 2026-10-21 05:59:59. La distribución por hora/día del resultado viene en hora local del comercio. | | `includeDeclined` | boolean | — | Incluir transacciones rechazadas para medir tasa de aprobación (por defecto true) | | `environment` | string (production | test) | — | "production" (por defecto) o "test" (modo de pruebas de tu cuenta) | | `currency` | array | — | Arreglo de códigos ISO, ej. ["CRC","USD"]; vacío = todas | **Devuelve** `{ summary, trends, environmentNote }` summary trae range, timezoneNote, totalRows, payments {total, approved, declined, approvalRate}, refunds {total, approved, failed, successRate}, byCurrency por moneda con pagos, costos desglosados (commission, iva_commission, cost, cost_iva, retention_iva, retention_rent, totalDeducted, taxWithholdings, pspCost), netToLiquidate, reconciles y reconciliationDelta; reembolsos; y netForPeriod. Además daily, sample, byWeekday, byHour, topCustomers, declineReasons, refundFailureReasons y transactionTypes. byWeekday, byHour y topCustomers vienen en null si la muestra es insuficiente (menos de 30 filas o menos de 5 días distintos). trends viene en null en ese mismo caso. Las horas y días están en UTC. ### Agente analista de ventas [#tilopay-analyze-sales] - `tilopay_analyze_sales` - Acceso: Sólo lectura - Operación del API: `POST /api/v1/consultTransactions (y análisis con modelo)` — https://tilopay.com/developers/api/procesos-operativos/consult-transactions Agente que analiza las transacciones de Tilopay en un rango de fechas y devuelve un informe en lenguaje natural: desempeño, tendencias, estacionalidad, calidad de aprobación, riesgos y recomendaciones accionables. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `startDate` | string | sí | Fecha inicial "YYYY-MM-DD HH:mm:ss". Fechas en UTC (formato YYYY-MM-DD HH:mm:ss). Costa Rica es UTC-6: el día local 2026-10-20 va de 2026-10-20 06:00:00 a 2026-10-21 05:59:59. La distribución por hora/día del resultado viene en hora local del comercio. | | `endDate` | string | sí | Fecha final "YYYY-MM-DD HH:mm:ss". Fechas en UTC (formato YYYY-MM-DD HH:mm:ss). Costa Rica es UTC-6: el día local 2026-10-20 va de 2026-10-20 06:00:00 a 2026-10-21 05:59:59. La distribución por hora/día del resultado viene en hora local del comercio. | | `question` | string | — | Pregunta o enfoque específico para el análisis (opcional) | | `environment` | string (production | test) | — | "production" (por defecto) o "test" (modo de pruebas de tu cuenta) | | `currency` | array | — | Arreglo de códigos ISO, ej. ["CRC","USD"]; vacío = todas | **Devuelve** `{ report, summary, trends, environmentNote }` report es el informe en lenguaje natural; summary y trends son los mismos de tilopay_sales_summary. Si no hay transacciones en el rango, devuelve solo un texto avisándolo, sin structuredContent. ### ¿Ya me pagó? [#tilopay-find-payment] - `tilopay_find_payment` - Acceso: Sólo lectura Busca si un cliente ya pagó: revisa los cobros de Tilopay y, si la sesión bancaria está abierta, también las entradas de la cuenta bancaria. Úsala para preguntas como '¿ya me pagó Ana?' o '¿entró el pago de ₡25.000?'. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `name` | string | — | Nombre del cliente (coincidencia parcial) | | `amount` | number | — | Monto del pago esperado | | `currency` | string | — | Moneda del monto, ej. CRC o USD | | `hours` | integer | — | Horas hacia atrás a revisar (por defecto 24) | | `reference` | string | — | Número de orden o referencia | **Devuelve** `{ found, bank_checked, payments }` payments = hasta 5 coincidencias con { source: "tilopay" | "baas", at, amount, currency, name, method, reference, email? }. ### Listar transacciones de Tilopay [#tilopay-list-transactions] - `tilopay_list_transactions` - Acceso: Sólo lectura - Operación del API: `POST /api/v1/consultTransactions` — https://tilopay.com/developers/api/procesos-operativos/consult-transactions Lista transacciones de Tilopay en un rango de fechas. Usa status para aprobadas/rechazadas y sort=newest para 'los últimos N' o 'la última'. Una sola llamada basta: no acortes el rango para buscar filas. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `startDate` | string | sí | Fecha inicial, ej. "2026-08-01 00:00:00". Fechas en UTC (formato YYYY-MM-DD HH:mm:ss). Costa Rica es UTC-6: el día local 2026-10-20 va de 2026-10-20 06:00:00 a 2026-10-21 05:59:59. La distribución por hora/día del resultado viene en hora local del comercio. | | `endDate` | string | sí | Fecha final, ej. "2026-08-31 23:59:59". Fechas en UTC (formato YYYY-MM-DD HH:mm:ss). Costa Rica es UTC-6: el día local 2026-10-20 va de 2026-10-20 06:00:00 a 2026-10-21 05:59:59. La distribución por hora/día del resultado viene en hora local del comercio. | | `status` | string (approved | declined | all) | — | approved = solo aprobadas, declined = solo rechazadas, all = todas | | `sort` | string (newest | oldest) | — | newest = más recientes primero | | `onlyAproved` | boolean | — | Compatibilidad: false equivale a status: "all" | | `environment` | string (production | test) | — | Ambiente, por defecto production | | `currency` | array | — | Monedas, ej. ["USD","CRC"] | | `orderNumber` | string | — | Filtrar por número de orden | | `email` | string | — | Filtrar por correo del cliente | | `limit` | integer | — | Máximo de filas a devolver | **Devuelve** `{ total, transactions[], environmentNote }` total = filas encontradas antes de aplicar limit; transactions = las filas devueltas; environmentNote avisa si el ambiente consultado no trajo filas. ### Consultar una transacción [#tilopay-get-transaction] - `tilopay_get_transaction` - Acceso: Sólo lectura - Operación del API: `POST /api/v1/consult` — https://tilopay.com/developers/api/procesos-operativos/consult Obtiene el detalle de una transacción específica de Tilopay a partir del número de orden. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `orderNumber` | string | sí | Número de orden de la transacción | | `merchantId` | string | — | ID de comercio (opcional) | **Devuelve** `{ result }` Respuesta cruda del API de Tilopay bajo la llave `result`. ### Capturar, reembolsar o reversar [#tilopay-modify-transaction] - `tilopay_modify_transaction` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones - Operación del API: `POST /api/v1/processModification` — https://tilopay.com/developers/api/procesos-operativos/process-modification Modifica una transacción de Tilopay: captura (capture), reembolso (refund) o reversión (reversal) por el monto indicado. El monto nunca puede superar el de la venta original: si el usuario pide más, díselo con el monto real de la venta y pregunta si reembolsa ese monto o una parte; no pidas confirmación de un monto mayor. Solo reembolsa ventas aprobadas, nunca una orden que ya es un reembolso (empieza con «Re-»). Cuando Tilopay confirma el reembolso se genera un comprobante en texto listo para reenviar al cliente. Operación sensible: afecta dinero real y requiere segundo factor. Llámala primero sin `confirmation_code`: se envía un código de 6 dígitos al correo del comercio y la respuesta trae `requires_confirmation`. Repite la misma llamada, con los mismos parámetros, agregando `confirmation_code`. Comunica el resultado exactamente como lo devuelve la herramienta (state): si es pendiente o no confirmado, nunca digas que el reembolso ya se hizo. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `orderNumber` | string | sí | Número de orden de la transacción | | `action` | string (capture | refund | reversal) | sí | Tipo de modificación | | `amount` | number | sí | Monto a modificar | | `currency` | string | — | Moneda del movimiento, ej. CRC o USD | | `client_name` | string | — | Nombre del cliente, para el comprobante | | `client_email` | string | — | Correo del cliente, para el comprobante | | `confirmation_code` | string | — | Código de 6 dígitos recibido por correo para autorizar la operación | **Devuelve** `{ result, state, receipt_code, receipt_url, receipt_text, receipt_whatsapp_url }` state = "approved" | "scheduled" | "unknown" | "failed"; el comprobante (receipt_*) sólo viene en reembolso o reversión aprobados. ### Historial de reembolsos [#tilopay-refunds-list] - `tilopay_refunds_list` - Acceso: Sólo lectura Reembolsos del comercio. pending=true devuelve los reembolsos pendientes de procesar; si no, el historial. Solo consulta: para reembolsar usa tilopay_modify_transaction. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `pending` | boolean | — | Solo pendientes | | `page` | integer | — | Página (por defecto 1) | | `limit` | integer | — | Registros por página (por defecto 20) | | `search` | string | — | Texto a buscar | **Devuelve** `{ result }` Listado de reembolsos tal como lo entrega Tilopay; con pending: true, sólo los pendientes. ### Cierre de caja programado [#tilopay-cash-close] - `tilopay_cash_close` - Acceso: Escritura Cierre de caja diario (se envía por WhatsApp): ventas del día por moneda, rechazos agrupados por motivo y la próxima liquidación de Tilopay. action 'get' muestra la configuración; 'set' la cambia (enabled, time_of_day 'HH:mm' en hora local, days 0=domingo…6=sábado; «de lunes a sábado» = [1,2,3,4,5,6]); 'preview' arma el cierre de hoy ahora. Para «apagá el cierre» usa set con enabled=false. Configurar es solo del dueño. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `action` | string (get | set | preview) | sí | "get" muestra la configuración, "set" la cambia (sólo el dueño), "preview" arma el cierre de hoy | | `enabled` | boolean | — | Sólo con set: true enciende, false apaga. Por defecto 20:00, lunes a sábado | | `time_of_day` | string | — | Hora local 'HH:mm' (24 h). 8 pm = '20:00' | | `days` | array | — | 0=domingo … 6=sábado | **Devuelve** Sólo texto: la configuración actual, o el cierre de hoy con preview. --- # Enlaces de pago > Herramientas del MCP para crear, consultar y borrar enlaces de pago, y preparar su envío. - kind: mcp-tool - status: stable - access: destructive - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/mcp/enlaces-de-pago ## Qué cubre [#que-cubre] Con este grupo el agente crea un enlace de cobro, consulta su detalle, lo borra y prepara el envío al cliente por WhatsApp o por correo. El envío por WhatsApp no manda el mensaje: devuelve un enlace listo para enviar. ## Herramientas [#herramientas] ### Crear cobro con enlace [#tilopay-create-charge] - `tilopay_create_charge` - Acceso: Escritura Crea un cobro y devuelve el enlace corto de Tilopay (tilo.co/s/…) que abre directo el formulario seguro de pago; si no está disponible, el enlace propio tilopay.shop/pagar/…. La respuesta trae url (la corta cuando exista) y fallback_url (la propia); ambas sirven. En WhatsApp envía de una vez el QR como imagen junto con el enlace; no llames la herramienta de QR después. Si faltan datos del cliente, la página del enlace los pide antes de cobrar. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `amount` | number | sí | Monto a cobrar | | `currency` | string | — | Moneda, ej. USD o CRC. Si se omite se usa la del país del comercio. | | `reference` | string | sí | Referencia del cobro en texto normal, con espacios. No convertir a slug ni reemplazar espacios por guiones o guiones bajos. | | `description` | string | sí | Concepto visible para el cliente. Conserva literalmente el texto del comercio con espacios, acentos y mayúsculas; por ejemplo 'prueba link', nunca 'prueba_link'. | | `client` | string | — | Nombre del cliente | | `client_email` | string | — | Correo del cliente | | `client_phone` | string | — | Teléfono del cliente | **Devuelve** `{ code, url, fallback_url, orderNumber }` url = enlace corto (tilo.co/s/… o https://tilopay.shop/pagar/{code}); fallback_url = este último. ### Detalle de un enlace de pago [#tilopay-get-payment-link] - `tilopay_get_payment_link` - Acceso: Sólo lectura - Operación del API: `GET /api/v1/getDetailLinkPayment/{link_payment_id}/{api_key}` — https://tilopay.com/developers/api/links-de-pago/detail-link-payment Obtiene el detalle de un enlace de pago de Tilopay por su ID. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `linkPaymentId` | string | sí | ID del enlace de pago | **Devuelve** `{ result }` Respuesta cruda del API de Tilopay bajo la llave `result`. ### Eliminar enlace de pago [#tilopay-delete-payment-link] - `tilopay_delete_payment_link` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones - Operación del API: `POST /api/v1/deleteLinkPayment` — https://tilopay.com/developers/api/links-de-pago/delete-link-payment Elimina un enlace de pago de Tilopay por su ID. Operación sensible: requiere segundo factor. Llámela primero sin `confirmation_code`: se envía un código de 6 dígitos al correo del comercio y la respuesta trae `requires_confirmation`. Repita la misma llamada agregando `confirmation_code`. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `id` | string | sí | ID del enlace de pago a eliminar | | `confirmation_code` | string | — | Código de 6 dígitos recibido por correo para autorizar la operación | **Devuelve** `{ result }` Respuesta cruda del API de Tilopay bajo la llave `result`. ### Enviar enlace de pago por WhatsApp [#tilopay-send-payment-link-whatsapp] - `tilopay_send_payment_link_whatsapp` - Acceso: Escritura Prepara el envío del enlace de pago por WhatsApp a un contacto: devuelve un enlace wa.me con el mensaje listo. Acepta el nombre de un contacto guardado o un teléfono. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `link_url` | string | sí | URL del enlace de pago | | `contact_name` | string | — | Nombre del contacto guardado o del cliente | | `phone` | string | — | Teléfono de WhatsApp, ej. +50688887777 | | `amount` | number | — | Sólo se usa para redactar el mensaje; no cambia el enlace | | `currency` | string | — | Sólo se usa para redactar el mensaje; no cambia el enlace | | `description` | string | — | Sólo se usa para redactar el mensaje; no cambia el enlace | | `message` | string | — | Texto propio del mensaje | | `save_contact` | boolean | — | Guardar el contacto en la agenda | | `send_now` | boolean | — | Obsoleto: se ignora. Siempre se devuelve el enlace wa.me para enviar con un toque. | **Devuelve** `{ to, message, whatsapp_url }` No envía el mensaje: devuelve el teléfono resuelto, el texto ya redactado y un enlace wa.me para enviarlo con un toque. Si no hay teléfono ni contacto guardado con ese nombre, devuelve error pidiéndolo. Guarda el contacto salvo que save_contact sea false. ### Enviar enlace de pago por correo [#tilopay-send-payment-link-email] - `tilopay_send_payment_link_email` - Acceso: Escritura Envía el enlace de pago por correo electrónico al cliente. Acepta el nombre de un contacto guardado o un correo. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `link_url` | string | sí | URL del enlace de pago | | `email` | string | — | Correo del destinatario | | `contact_name` | string | — | Nombre del contacto guardado o del cliente | | `amount` | number | — | Sólo se usa para redactar el mensaje; no cambia el enlace | | `currency` | string | — | Sólo se usa para redactar el mensaje; no cambia el enlace | | `description` | string | — | Sólo se usa para redactar el mensaje; no cambia el enlace | | `message` | string | — | Nota adicional para el cliente | | `save_contact` | boolean | — | Guardar el contacto en la agenda | **Devuelve** `{ sent, to }` sent es true y to el correo al que se envió. Si no hay correo ni contacto guardado con ese nombre, devuelve error pidiéndolo. ### QR de un enlace de pago o producto [#tilopay-payment-link-qr] - `tilopay_payment_link_qr` - Acceso: Sólo lectura Genera el QR de un enlace de pago o de un producto del catálogo y lo envía como imagen (PNG) (el envío como imagen es solo en el Asistente de WhatsApp; en otros clientes se usa qr_url). Úsala cuando el comercio pida el QR para compartir o imprimir. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `link_url` | string | — | Enlace de pago completo (https://...) | | `catalog_id` | string | — | ID del producto del catálogo | | `label` | string | — | Nombre para el pie de la imagen | **Devuelve** `{ link, qr_url }` link = enlace de pago; qr_url = imagen del código QR. ### QR permanente de monto abierto [#tilopay-static-payment-qr] - `tilopay_static_payment_qr` - Acceso: Sólo lectura Devuelve el enlace y el QR permanente de monto abierto del comercio (el cliente escanea, digita el monto y paga). Solo consulta: si el comercio no lo tiene activado, lo explica y no lo activa. **Parámetros** Sin parámetros. **Devuelve** `{ enabled, link, qr_url }` enabled = si el QR estático está activo; link = enlace fijo del comercio; qr_url = imagen del código QR. --- # Catálogo > Herramientas del MCP para consultar, crear, editar y eliminar productos y servicios de tu catálogo, y obtener feeds para otros canales. - kind: mcp-tool - status: stable - access: destructive - last_verified: 2026-10-20 - url: https://tilopay.com/developers/agentes/mcp/catalogo ## Qué cubre [#que-cubre] Podés listar tus productos y servicios, consultar su detalle, crear nuevos, editarlos o eliminarlos, y obtener feeds para otros canales. Eliminar un producto es una operación sensible: el Asistente de WhatsApp pide confirmación en el chat y los clientes MCP deben pedir confirmación humana; no exige código por correo. ## Herramientas [#herramientas] ### Listar catálogo de productos o servicios [#tilopay-catalog-list-items] - `tilopay_catalog_list_items` - Acceso: Sólo lectura - Operación del API: `GET /api/v1/getLinkPaymentList/{api_key}/{limit}` — https://tilopay.com/developers/api/links-de-pago/payment-item-list Lista los productos o servicios del catálogo de Tilopay (título, precio y enlace corto). Permite buscar por nombre o descripción (sin importar acentos ni mayúsculas). El listado de Tilopay puede tardar unos minutos en reflejar cambios hechos en el panel; lo creado desde aquí aparece de inmediato y la respuesta de tilopay_catalog_create_item ya trae el ítem nuevo. Usa refresh=true para forzar lectura fresca. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `limit` | integer | — | Máximo de ítems (por defecto 50) | | `search` | string | — | Texto a buscar en el nombre del producto | | `page` | integer | — | Página (por defecto 1) | | `refresh` | boolean | — | true para ignorar la memoria corta y leer de nuevo | | `include_qr` | boolean | — | Incluir el QR completo en base64 de cada ítem (por defecto false; el listado devuelve solo el enlace y has_qr) | **Devuelve** `{ result }` Respuesta cruda del API de Tilopay bajo la llave `result`. ### Detalle de un ítem del catálogo [#tilopay-catalog-get-item] - `tilopay_catalog_get_item` - Acceso: Sólo lectura - Operación del API: `GET /api/v1/getLinkPaymentById/{link_payment_id}/{api_key}` — https://tilopay.com/developers/api/links-de-pago/payment-by-id Obtiene el detalle de un producto o servicio del catálogo de Tilopay por su ID. El QR en base64 solo con include_qr=true. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `itemId` | string | sí | ID del ítem del catálogo | | `include_qr` | boolean | — | Incluir el QR en base64 (por defecto false; úsalo solo si el comercio pide el QR) | **Devuelve** `{ result }` Respuesta cruda del API de Tilopay bajo la llave `result`. ### Agregar producto o servicio al catálogo [#tilopay-catalog-create-item] - `tilopay_catalog_create_item` - Acceso: Escritura - Operación del API: `POST /api/v1/createLinkPayment` — https://tilopay.com/developers/api/links-de-pago/create-link-payment Crea un producto o servicio en el catálogo de Tilopay con su precio y devuelve el enlace corto de pago y el QR como imagen. Si el comercio envió una foto por WhatsApp en los últimos 10 minutos, la usa como imagen del producto (solo en el Asistente de WhatsApp). **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `name` | string | sí | Nombre del producto o servicio (título del enlace) | | `amount` | number | sí | Precio | | `currency` | string | — | Moneda, ej. CRC o USD (por defecto la del comercio) | | `description` | string | — | Descripción corta | | `media_ref` | string | — | Referencia exacta de la imagen recibida por WhatsApp, si la conoce | | `use_last_image` | boolean | — | false para crear el producto sin foto aunque haya una imagen reciente | **Devuelve** `{ result, linkId, url }` result = respuesta del API tal cual; linkId = id del enlace de pago que representa el producto; url = enlace de cobro del producto. ### Editar un producto del catálogo [#tilopay-catalog-update-item] - `tilopay_catalog_update_item` - Acceso: Escritura Edita un producto del catálogo (nombre, precio, moneda, descripción o foto) sin cambiar su enlace de pago. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `itemId` | string | sí | ID del ítem del catálogo | | `name` | string | — | Nuevo nombre | | `amount` | number | — | Nuevo precio | | `currency` | string | — | Nueva moneda | | `description` | string | — | Nueva descripción corta | | `media_ref` | string | — | Referencia exacta de la imagen recibida por WhatsApp, si la conoce | | `use_last_image` | boolean | — | false para no cambiar la foto aunque haya una imagen reciente | **Devuelve** `{ item, short_link, changed }` item = el producto actualizado; short_link = su enlace de pago (no cambia); changed = los campos que cambiaron. Cambiar el monto o la moneda es sólo para el dueño del comercio. ### Borrar un producto del catálogo [#tilopay-catalog-delete-item] - `tilopay_catalog_delete_item` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones - Operación del API: `POST /api/v1/deleteLinkPayment` — https://tilopay.com/developers/api/links-de-pago/delete-link-payment Borra un producto del catálogo de Tilopay y su enlace de pago deja de funcionar. No exige código por correo. En el Asistente de WhatsApp pide confirmación en el chat; en clientes MCP la confirmación humana queda a cargo del cliente. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `itemId` | string | sí | ID del ítem del catálogo | **Devuelve** `{ result }` result = respuesta del API al borrar el enlace de pago que representa el producto. ### Sincronizar catálogo con redes y buscadores [#tilopay-catalog-feed] - `tilopay_catalog_feed` - Acceso: Escritura Entrega el enlace del catálogo sincronizado y los pasos para conectarlo en Facebook/Instagram, Google Shopping, TikTok o Pinterest (un canal a la vez, el que pida el comercio). Con send_email=true lo manda al correo del comercio. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `platform` | string (facebook | google | tiktok | pinterest) | — | Canal pedido. Si el comercio no dijo cuál, NO llames: pregúntale primero. | | `send_email` | boolean | — | true si pidió que se lo mandes por correo | **Devuelve** `{ url, urls, omitted_without_photo, platform }` url = feed del canal pedido; urls = [{ currency, url }] por moneda; omitted_without_photo = productos omitidos por no tener foto. --- # Contactos > Herramientas del MCP para la agenda del comercio: ver, guardar y borrar contactos. - kind: mcp-tool - status: stable - access: destructive - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/mcp/contactos ## Qué cubre [#que-cubre] La agenda le permite al agente reutilizar teléfono y correo al enviar un enlace de pago, sin volver a pedirlos. Borrar un contacto es irreversible. ## Herramientas [#herramientas] ### Guardar contacto [#tilopay-save-contact] - `tilopay_save_contact` - Acceso: Escritura Guarda o actualiza un contacto del comercio (nombre, teléfono de WhatsApp y correo) para reutilizarlo en envíos. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `name` | string | sí | Nombre del contacto (el contacto se identifica por nombre) | | `phone` | string | — | Teléfono de WhatsApp, ej. +50688887777 | | `email` | string | — | Correo del contacto (se guarda sólo si es válido) | | `note` | string | — | Nota interna | **Devuelve** `{ contact }` El contacto guardado o actualizado. ### Ver contactos [#tilopay-list-contacts] - `tilopay_list_contacts` - Acceso: Sólo lectura Lista los contactos guardados del comercio; opcionalmente filtra por nombre. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `search` | string | — | Texto a buscar en el nombre | **Devuelve** `{ contacts }` Lista de contactos guardados del comercio. ### Eliminar contacto [#tilopay-delete-contact] - `tilopay_delete_contact` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones Elimina un contacto guardado del comercio por su nombre. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `name` | string | sí | Nombre del contacto | **Devuelve** `{ removed }` removed es true. Si no existe un contacto con ese nombre, devuelve error. --- # Perfil del negocio y recetas > Herramientas del MCP para ver y completar el perfil del negocio y obtener recetas de automatización a partir de ese perfil. - kind: mcp-tool - status: stable - access: write - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/mcp/perfil ## Qué cubre [#que-cubre] El agente guarda un perfil corto del negocio: a qué se dedica, qué vende, por dónde vende, cómo son sus cobros y qué quiere mejorar. Con ese perfil arma las recetas de automatización que le propone al comercio, y sabe cuál es la siguiente pregunta que corresponde hacer (el cuestionario es de cuatro preguntas como máximo). El perfil se guarda campo por campo: lo que no se envía se conserva. Las recetas cambian según los módulos que el usuario tenga activos: las recetas bancarias sólo aparecen si tiene habilitado el [API bancario](/developers/agentes/mcp/api-bancario). Estas herramientas no llaman al API de Tilopay: trabajan sobre los datos del propio servidor MCP. ## Herramientas [#herramientas] ### Ver perfil del negocio [#tilopay-get-business-profile] - `tilopay_get_business_profile` - Acceso: Sólo lectura Devuelve el perfil del negocio: los datos que ya trae la cuenta de Tilopay (nombre, giro, ubicación, teléfono, correo de facturación, monedas, logo) y los que faltan por preguntar, con la siguiente pregunta pendiente. **Parámetros** Sin parámetros. **Devuelve** `{ profile, next_question, total_questions, is_complete }` profile = el perfil guardado del negocio (o null si no hay); next_question = la siguiente pregunta pendiente del onboarding; total_questions = cuántas preguntas tiene el cuestionario; is_complete = si el perfil ya está completo. ### Guardar perfil del negocio [#tilopay-save-business-profile] - `tilopay_save_business_profile` - Acceso: Escritura Guarda o completa el perfil del negocio con lo que el comercio respondió o confirmó. Puede guardar un campo a la vez; los campos que no se envían se conservan y lo guardado aquí ya no se sobrescribe con los datos de Tilopay. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `business_type` | string | — | A qué se dedica el negocio | | `main_products` | string | — | Productos o servicios principales | | `sales_channels` | string | — | Canales de venta: local, en línea, redes, WhatsApp | | `ticket_pattern` | string | — | Cómo son los cobros: montos, frecuencia, moneda | | `goals` | string | — | Qué quiere mejorar el comercio | | `notes` | string | — | Detalles adicionales útiles | | `opening_hours` | string | — | Horario de atención | | `tone` | string | — | Tono de comunicación con los clientes | | `short_description` | string | — | Descripción corta del negocio | | `social_links` | string | — | Sitio web y redes sociales | | `refund_policy` | string | — | Política de devoluciones o reembolsos | | `business_name` | string | — | Corrección del nombre del negocio | | `industry` | string | — | Corrección del giro del negocio | | `phone` | string | — | Corrección del teléfono del negocio | | `address` | string | — | Corrección de la dirección | | `invoice_email` | string | — | Corrección del correo de facturación | **Devuelve** `{ profile, next_question, is_complete }` profile = el perfil ya actualizado (los campos que no se envían se conservan); next_question = la siguiente pregunta pendiente; is_complete = si con este guardado el perfil quedó completo. ### Recetas y automatizaciones [#tilopay-recommend-automations] - `tilopay_recommend_automations` - Acceso: Sólo lectura Devuelve recetas y automatizaciones sugeridas para el comercio según su perfil de negocio y los módulos del MCP que tiene activos. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `limit` | integer | — | Cuántas recetas devolver (por defecto 5) | **Devuelve** `{ profile_complete, next_question, recipes }` recipes = recetas y automatizaciones sugeridas según el perfil del negocio y los módulos activos (incluye las bancarias sólo si el usuario tiene BaaS habilitado); profile_complete y next_question indican si falta completar el perfil. --- # Microtienda y pedidos > Herramientas del MCP para armar microtiendas con carrito desde el catálogo y administrar los pedidos que entran por ahí. - kind: mcp-tool - status: stable - access: destructive - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/mcp/microtienda ## Qué cubre [#que-cubre] Con los productos del [catálogo](/developers/agentes/mcp/catalogo) el agente arma una **microtienda con carrito**: una página pública con varios productos donde el cliente elige cantidades y paga todo junto. Cada microtienda tiene su propio enlace. La segunda mitad del grupo es la **gestión de pedidos**: se activa una vez (nombre de la tienda, logo opcional y hora del recordatorio diario), y a partir de ahí el comercio puede ver el resumen, listar pedidos por estado, ver los que están pagados sin entregar y marcarlos como entregados. Los estados de un pedido son `pending` (sin pagar), `paid` (pagado sin entregar) y `delivered` (entregado). Desactivar una microtienda o apagar la gestión de pedidos no borra los productos del catálogo ni los pedidos ya registrados. Estas herramientas no llaman al API de Tilopay: trabajan sobre los datos del propio servidor MCP, salvo el cobro, que sale por el enlace de pago de cada producto. ## Herramientas [#herramientas] ### Crear una microtienda con carrito [#tilopay-store-create] - `tilopay_store_create` - Acceso: Escritura Crea un enlace de microtienda para compartir con un cliente: muestra los productos del catálogo, el cliente arma un carrito y al finalizar paga desde la misma página con un enlace que incluye el detalle del carrito. Por defecto incluye todo el catálogo; se puede limitar a ciertos IDs de productos. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `title` | string | — | Título visible de la tienda | | `item_ids` | array | — | IDs de productos del catálogo a mostrar; si se omite, se muestra todo el catálogo | **Devuelve** `{ slug, url, items }` slug = identificador de la microtienda; url = enlace público de la tienda con carrito; items = cuántos productos del catálogo quedaron incluidos. ### Listar microtiendas activas [#tilopay-store-list] - `tilopay_store_list` - Acceso: Sólo lectura Lista las microtiendas activas del comercio con su enlace para compartir. **Parámetros** Sin parámetros. **Devuelve** `{ stores[] }` stores = microtiendas activas con slug, título, enlace público y los ids de productos que incluye cada una. ### Desactivar una microtienda [#tilopay-store-delete] - `tilopay_store_delete` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones Desactiva una microtienda por su slug: el enlace deja de abrir. Confirma con el comercio antes de usarla. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `slug` | string | sí | Slug de la tienda (el final de su enlace) | **Devuelve** `{ slug, active }` Desactiva la microtienda: el enlace deja de mostrar productos. active queda en false; los productos del catálogo no se borran. ### Conectar un dominio propio a la tienda [#tilopay-store-domain-connect] - `tilopay_store_domain_connect` - Acceso: Escritura Conecta un dominio propio del comercio (ej. tienda.minegocio.com) a su microtienda. Lo registra de inmediato y devuelve la instrucción CNAME. Úsala solo cuando el comercio dé el dominio. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `hostname` | string | sí | Dominio, ej. tienda.minegocio.com | | `slug` | string | — | Slug de la tienda; si se omite, la más reciente | **Devuelve** ### Estado de los dominios propios [#tilopay-store-domain-status] - `tilopay_store_domain_status` - Acceso: Sólo lectura Revisa el estado de los dominios propios de las tiendas del comercio (vía Cloudflare). **Parámetros** Sin parámetros. **Devuelve** `{ domains }` domains = dominios propios conectados al comercio y su estado. ### Quitar un dominio propio [#tilopay-store-domain-remove] - `tilopay_store_domain_remove` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones Desconecta un dominio propio de la tienda; la tienda sigue en su dirección tilopay.shop. Confirma con el comercio antes de usarla. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `hostname` | string | sí | Dominio propio a desconectar (4–253 caracteres), conectado por ese comercio | **Devuelve** `{ hostname, removed }` hostname = dominio desconectado; removed = true si quedó removido. ### Activar o configurar la gestión de pedidos [#tilopay-orders-setup] - `tilopay_orders_setup` - Acceso: Escritura Activa el control de pedidos de la microtienda y guarda el nombre de la tienda, el logo y la hora del recordatorio diario de pedidos pagados sin entregar. Sirve también para cambiar cualquiera de esos datos después. El logo puede venir como enlace https de una imagen o como la imagen que el comercio acaba de enviar por WhatsApp (pase la referencia que aparece en el mensaje). **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `store_name` | string | — | Nombre visible de la tienda | | `logo` | string | — | Enlace https de la imagen del logo, o la referencia de la imagen enviada por WhatsApp | | `reminder_time` | string | — | Hora local del recordatorio diario en formato HH:mm (ej. "18:00"); vacío lo desactiva | **Devuelve** `{ orders_enabled, store_name, has_logo, reminder_time }` Deja la gestión de pedidos activa y devuelve la configuración resultante: nombre de la tienda que ven los clientes, si hay logo cargado y la hora del recordatorio diario de pedidos pendientes. ### Ver la configuración de la tienda y los pedidos [#tilopay-orders-settings] - `tilopay_orders_settings` - Acceso: Sólo lectura Muestra si la gestión de pedidos está activa, el nombre de la tienda, si hay logo y la hora del recordatorio diario. **Parámetros** Sin parámetros. **Devuelve** `{ orders_enabled, store_name, has_logo, reminder_time }` Configuración actual de la tienda y de los pedidos, sin cambiar nada. ### Resumen de pedidos [#tilopay-orders-status] - `tilopay_orders_status` - Acceso: Sólo lectura Resumen de los pedidos de las microtiendas: cuántos están pendientes de pago, cuántos pagados sin entregar (con su monto) y cuántos se entregaron hoy. **Parámetros** Sin parámetros. **Devuelve** `{ pending, paid, delivered, ... }` Resumen de pedidos: cuántos están pendientes de pago, pagados sin entregar y entregados, con los montos del período. ### Listar pedidos [#tilopay-orders-list] - `tilopay_orders_list` - Acceso: Sólo lectura Lista los pedidos de las microtiendas con su código, cliente, total y detalle. Se puede filtrar por estado (pending = pendiente de pago, paid = pagado sin entregar, delivered = entregado) y por los últimos días. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `status` | string (pending | paid | delivered | all) | — | Estado del pedido; por defecto todos | | `days` | integer | — | Solo pedidos de los últimos N días | | `limit` | integer | — | 1–100 (25 por defecto) | **Devuelve** `{ orders[] }` orders = pedidos con código, cliente, total, moneda, estado y fecha. Se puede filtrar por estado (pending, paid, delivered, all) y por los últimos días. ### Pedidos pagados sin entregar [#tilopay-orders-pending] - `tilopay_orders_pending` - Acceso: Sólo lectura Lista los pedidos ya pagados que aún no se han entregado. Es la herramienta que usa el recordatorio diario. **Parámetros** Sin parámetros. **Devuelve** `{ pending, orders[] }` pending = cuántos pedidos están pagados y sin entregar; orders = esos pedidos con código, cliente, total y moneda. ### Marcar un pedido como entregado [#tilopay-order-mark-delivered] - `tilopay_order_mark_delivered` - Acceso: Escritura Marca uno o varios pedidos como entregados. Acepta el código del pedido (ej. "#A3F2", incluso varios en el mismo mensaje) o el nombre del cliente. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `code` | string | — | Código del pedido, ej. "#A3F2"; pueden venir varios | | `client` | string | — | Nombre del cliente del pedido | **Devuelve** `{ delivered, missing }` delivered = cuántos pedidos quedaron marcados como entregados; missing = los códigos que no se encontraron. ### Apagar la gestión de pedidos [#tilopay-orders-disable] - `tilopay_orders_disable` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones Apaga el control de pedidos y cancela el recordatorio diario. Los pedidos ya registrados se conservan. Pida un sí explícito antes de usarla. **Parámetros** Sin parámetros. **Devuelve** `{ orders_enabled: false }` Apaga la gestión de pedidos. Los pedidos ya registrados se conservan. --- # Avisos y notificaciones > Herramientas del MCP para ver y cambiar los avisos por WhatsApp del comercio: cobros aprobados, cobros fallidos, resumen diario y pedidos. - kind: mcp-tool - status: stable - access: write - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/mcp/avisos ## Qué cubre [#que-cubre] El agente puede avisarle al comercio por WhatsApp cuando entra un cobro, cuando un cobro se rechaza, cuando entra un pedido, y enviarle un resumen diario a la hora que elija. Estas dos herramientas son las que leen y cambian esa configuración. No envían mensajes por su cuenta: solamente prenden, apagan y consultan los avisos. Los campos que no se envían se conservan. ## Herramientas [#herramientas] ### Ver la configuración de avisos [#tilopay-get-notification-settings] - `tilopay_get_notification_settings` - Acceso: Sólo lectura Muestra cómo están configurados los avisos del comercio: si los pagos recibidos se avisan por WhatsApp y/o por correo, a qué correo, desde qué monto y si hay horario de silencio. **Parámetros** Sin parámetros. **Devuelve** `{ settings }` settings = configuración de avisos del comercio: qué avisos por WhatsApp están encendidos (cobros aprobados, cobros fallidos, resumen diario, pedidos) y a qué hora se envía el resumen. ### Configurar los avisos del comercio [#tilopay-set-notification-settings] - `tilopay_set_notification_settings` - Acceso: Escritura Cambia la configuración de avisos del comercio: activar o desactivar el aviso de pago recibido por WhatsApp y por correo, el correo de destino, el monto mínimo para avisar y el horario de silencio (en la hora local del comercio). Solo envíe los campos que el usuario pidió cambiar. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `payment_whatsapp` | boolean | — | Avisar por WhatsApp cuando se recibe un pago | | `payment_email` | boolean | — | Avisar por correo cuando se recibe un pago | | `notify_email` | string | — | Correo que recibe los avisos (si se omite, el de la cuenta) | | `min_amount` | number | — | Monto mínimo para avisar (0 = avisar por cualquier monto) | | `quiet_from` | integer | null | — | Hora local en que empieza el silencio (null para quitarlo) | | `quiet_to` | integer | null | — | Hora local en que termina el silencio (null para quitarlo) | **Devuelve** `{ settings }` settings = la configuración de avisos ya actualizada. Los campos que no se envían se conservan. --- # Comprobantes de cobro > Herramientas del MCP para listar los comprobantes de los cobros aprobados y reenviarle a un cliente el comprobante de su pago. - kind: mcp-tool - status: stable - access: write - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/mcp/comprobantes ## Qué cubre [#que-cubre] Cada cobro aprobado que pasa por el agente genera un comprobante con su propio código, una página para verlo y una imagen para compartir. Con estas dos herramientas el comercio lista los comprobantes de un período y reenvía uno al cliente por WhatsApp. El comprobante es un documento informativo del cobro. No es una factura electrónica. ## Herramientas [#herramientas] ### Listar comprobantes de cobro [#tilopay-list-receipts] - `tilopay_list_receipts` - Acceso: Sólo lectura Lista los últimos comprobantes de cobro del comercio (monto, cliente, orden y código). Cada uno trae un texto listo para reenviar al cliente. No cobra nada. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `limit` | integer | — | Cuántos comprobantes listar (5 por defecto) | **Devuelve** `{ receipts[] }` receipts = comprobantes de cobro con código, monto, moneda, cliente, número de orden, fecha de pago, enlace de la página del comprobante y enlace de la imagen. ### Reenviar el comprobante de un cobro al cliente [#tilopay-send-receipt] - `tilopay_send_receipt` - Acceso: Escritura Envía al cliente el comprobante de un cobro, por WhatsApp (por defecto: enlace wa.me de un toque) o por correo con la marca del comercio (channel=email). Busca por código, número de orden o nombre del cliente; sin datos usa el comprobante más reciente. Si el usuario dice «el último cobro» o «el último comprobante», llámala directamente sin code ni order_number (no consultes transacciones antes). Usa send_now solo si el usuario pide que se envíe directamente por WhatsApp. Nunca inventes el correo ni el teléfono del cliente: si faltan, pídelos. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `code` | string | — | Código del comprobante (8 caracteres) | | `order_number` | string | — | Número de orden del cobro | | `client_name` | string | — | Nombre del cliente del cobro, para buscar el comprobante | | `channel` | string (whatsapp | email) | — | whatsapp (por defecto) o email | | `email` | string | — | Correo del cliente, si se envía por correo | | `contact_name` | string | — | Nombre del contacto guardado o del cliente | | `phone` | string | — | Teléfono de WhatsApp, ej. +50688887777 | | `message` | string | — | Texto propio para acompañar el comprobante | | `save_contact` | boolean | — | Guardar el contacto en la agenda | | `send_now` | boolean | — | true envía el comprobante directamente al cliente; por defecto se entrega el enlace wa.me | **Devuelve** `{ sent | code, page_url, image_url, whatsapp_url }` Reenvía el comprobante al cliente por WhatsApp: devuelve el código del comprobante, el enlace de su página, el de la imagen y, cuando no se envía directo, el enlace de WhatsApp listo para abrir. --- # Recordatorios > Herramientas del MCP para crear, ver y cancelar recordatorios por WhatsApp, con o sin una acción del agente al enviarse. - kind: mcp-tool - status: stable - access: destructive - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/mcp/recordatorios ## Qué cubre [#que-cubre] Un recordatorio es un mensaje de WhatsApp programado: una sola vez, diario, semanal o mensual. Puede ser sólo texto o traer una **acción** que el agente ejecuta al enviarlo, escrita en lenguaje natural ("dame el resumen de ventas de hoy", "listá los enlaces de pago sin cobrar"), y el resultado se adjunta al mensaje. Reglas que conviene tener claras: - Las horas son la hora local del comercio, según el país de su teléfono de WhatsApp. - Hay un máximo de 20 recordatorios activos. - Los recordatorios de enlaces de pago o de cobros **siempre** llegan al WhatsApp del comercio, nunca al cliente. - Para enviar a otro número, primero hay que guardarlo como [contacto](/developers/agentes/mcp/contactos). ## Herramientas [#herramientas] ### Crear recordatorio [#tilopay-create-reminder] - `tilopay_create_reminder` - Acceso: Escritura Crea un recordatorio por WhatsApp, de una sola vez o recurrente (diario, semanal o mensual). Puede ser solo texto o ejecutar una acción del agente al enviarse (con `action`): resumen de ventas, transacciones del día, enlaces pendientes, etc. NO crea recordatorios bancarios (saldo, movimientos, estados de cuenta, transferencias): esos los configura el comercio en el calendario del portal de Banca Cliente. Si el recordatorio es para enviar un enlace de pago o cobro, SIEMPRE llega al WhatsApp del comercio que lo pidió, nunca al cliente. En los demás casos se envía al WhatsApp del comercio o a un contacto ya guardado (contact_name); si el usuario da un teléfono nuevo, hay que guardarlo primero con tilopay_save_contact. Máximo 20 recordatorios activos. El mensaje sale con un prefijo fijo que identifica al comercio. Horas en la hora local del comercio (según el país de su teléfono de WhatsApp). **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `message` | string | sí | Texto del recordatorio (máx. 500 caracteres, sin HTML) | | `action` | string | — | Instrucción que el agente ejecutará al enviarlo, en lenguaje natural, ej. 'dame el resumen de ventas de hoy' o 'lista los enlaces de pago pendientes'. El resultado se adjunta al mensaje. Omítelo si es un recordatorio de solo texto. | | `schedule` | string (once | daily | weekly | monthly) | sí | Frecuencia: once = una sola vez | | `when` | string | — | Solo para once: fecha y hora local 'YYYY-MM-DD HH:mm' | | `time_of_day` | string | — | Para recurrentes: hora local 'HH:mm' | | `weekday` | integer | — | Para weekly: 0 = domingo ... 6 = sábado | | `day_of_month` | integer | — | Para monthly: día del mes (1-28) | | `contact_name` | string | — | Nombre de un contacto ya guardado (mcp_contact) que debe recibirlo. Si se omite, llega al WhatsApp del comercio. No se aceptan teléfonos nuevos: guárdalos primero con tilopay_save_contact. | **Devuelve** `{ id, message, action, phone, contact_name, schedule, when, next_run_local, is_active }` El recordatorio creado: cuándo se envía en la hora local del comercio, a qué número, y qué acción del agente se ejecuta al enviarse. Máximo 20 recordatorios activos; los de enlaces de cobro siempre llegan al WhatsApp del comercio, nunca al cliente. ### Ver recordatorios [#tilopay-list-reminders] - `tilopay_list_reminders` - Acceso: Sólo lectura Lista los recordatorios activos del comercio con su próxima fecha de envío. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `include_inactive` | boolean | — | true para incluir los ya enviados o cancelados | **Devuelve** `{ reminders[] }` reminders = recordatorios del comercio con su mensaje, frecuencia, próxima ejecución en hora local y si están activos. ### Cancelar recordatorio [#tilopay-cancel-reminder] - `tilopay_cancel_reminder` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones Cancela un recordatorio por su ID o buscando parte de su texto. No borra el historial, solo deja de enviarse. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `id` | string | — | ID del recordatorio | | `search` | string | — | Parte del texto del recordatorio | **Devuelve** `{ cancelled }` cancelled = el recordatorio que quedó desactivado. --- # Cobros recurrentes > Herramientas del MCP para consultar planes recurrentes, suscriptores y sus pagos, y para pausar, reactivar o eliminar un suscriptor. - kind: mcp-tool - status: stable - access: destructive - last_verified: 2026-10-20 - url: https://tilopay.com/developers/agentes/mcp/recurrentes ## Qué cubre [#que-cubre] Cuatro herramientas de lectura sobre los planes de cobro recurrente y sus suscriptores, y una sensible que pausa, reactiva o elimina un suscriptor. Esa última afecta cobros futuros: pedí confirmación humana antes de ejecutarla. ## Herramientas [#herramientas] ### Listar planes de cobro recurrente [#tilopay-recurring-list-plans] - `tilopay_recurring_list_plans` - Acceso: Sólo lectura - Operación del API: `POST /api/v1/getPlansRepeat` — https://tilopay.com/developers/api/recurrentes/planes/get-plans Lista los planes de cobro recurrente configurados en Tilopay. **Parámetros** Sin parámetros. **Devuelve** `{ result }` Respuesta cruda del API de Tilopay bajo la llave `result`. ### Detalle de un plan recurrente [#tilopay-recurring-get-plan] - `tilopay_recurring_get_plan` - Acceso: Sólo lectura - Operación del API: `POST /api/v1/getPlanRepeat` — https://tilopay.com/developers/api/recurrentes/planes/get-plan Obtiene el detalle de un plan de cobro recurrente por su ID. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `id` | string | sí | ID del plan | | `include_qr` | boolean | — | Incluir el QR en base64 del plan (por defecto false; úsalo solo si el comercio pide el QR) | **Devuelve** `{ result }` Respuesta cruda del API de Tilopay bajo la llave `result`. ### Detalle de un suscriptor [#tilopay-recurring-get-subscriber] - `tilopay_recurring_get_subscriber` - Acceso: Sólo lectura - Operación del API: `POST /api/v1/getSuscriptorRepeat` — https://tilopay.com/developers/api/recurrentes/suscriptores/get-suscriptor-plan Obtiene el detalle de un suscriptor de un plan recurrente por su ID. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `id` | string | sí | ID del suscriptor | **Devuelve** `{ result }` Respuesta cruda del API de Tilopay bajo la llave `result`. ### Buscar suscriptor por nombre o correo [#tilopay-recurring-find-subscriber] - `tilopay_recurring_find_subscriber` - Acceso: Sólo lectura Busca un suscriptor por nombre o correo en todos los planes recurrentes de una sola vez. Úsala antes de pausar, reactivar o editar a alguien cuando no tienes su ID. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `query` | string | sí | Nombre o correo del suscriptor | **Devuelve** `{ result }` result = suscriptores que coinciden, cada uno con su plan_id y plan. ### Pagos de un suscriptor [#tilopay-recurring-subscriber-payments] - `tilopay_recurring_subscriber_payments` - Acceso: Sólo lectura - Operación del API: `POST /api/v1/getSuscriptorPayments` — https://tilopay.com/developers/api/recurrentes/suscriptores/suscriptor-payments Lista los pagos realizados por un suscriptor recurrente. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `id` | string | sí | ID del suscriptor | **Devuelve** `{ result }` Respuesta cruda del API de Tilopay bajo la llave `result`. ### Cobros recurrentes fallidos [#tilopay-recurring-failed-payments] - `tilopay_recurring_failed_payments` - Acceso: Sólo lectura - Operación del API: `POST /api/v1/getSuscriptorPayments` — https://tilopay.com/developers/api/recurrentes/suscriptores/suscriptor-payments Lista los últimos cobros recurrentes que fallaron (plan, suscriptor, monto, fecha y motivo en lenguaje simple). Una sola llamada basta. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `limit` | integer | — | Máximo de cobros (por defecto 10) | | `startDate` | string | — | Desde, "YYYY-MM-DD HH:mm:ss". Fechas en UTC (formato YYYY-MM-DD HH:mm:ss). Costa Rica es UTC-6: el día local 2026-10-20 va de 2026-10-20 06:00:00 a 2026-10-21 05:59:59. La distribución por hora/día del resultado viene en hora local del comercio. | | `endDate` | string | — | Hasta, "YYYY-MM-DD HH:mm:ss". Fechas en UTC (formato YYYY-MM-DD HH:mm:ss). Costa Rica es UTC-6: el día local 2026-10-20 va de 2026-10-20 06:00:00 a 2026-10-21 05:59:59. La distribución por hora/día del resultado viene en hora local del comercio. | **Devuelve** `{ total, source, failures[] }` failures = cobros recurrentes rechazados, con plan, suscriptor, monto, moneda y motivo del rechazo; total = cuántos se encontraron; source = la ruta del API de la que se obtuvieron. Combina la consulta de planes, suscriptores y sus pagos. ### Pausar, reactivar o eliminar un suscriptor [#tilopay-recurring-manage-subscriber] - `tilopay_recurring_manage_subscriber` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones - Operación del API: `POST /api/v1/pauseSuscriptorRepeat, /reactiveSuscriptorRepeat o /deleteSuscriptorRepeat` — https://tilopay.com/developers/api/recurrentes/suscriptores/pause-suscriptor-plan Pausa, reactiva o elimina un suscriptor de un plan recurrente en Tilopay. Operación sensible: afecta cobros futuros y requiere segundo factor. Llámela primero sin `confirmation_code`: se envía un código de 6 dígitos al correo del comercio y la respuesta trae `requires_confirmation`. Repita la misma llamada agregando `confirmation_code`. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `idSubscriber` | string | sí | ID del suscriptor | | `action` | string (pause | reactivate | delete) | sí | Acción a realizar | | `confirmation_code` | string | — | Código de 6 dígitos recibido por correo para autorizar la operación | **Devuelve** `{ result }` Respuesta cruda del endpoint correspondiente a la acción: pause, reactivate o delete. ### Crear plan de suscripción [#tilopay-recurring-create-plan] - `tilopay_recurring_create_plan` - Acceso: Escritura - Operación del API: `POST /api/v1/createPlanRepeat` — https://tilopay.com/developers/api/recurrentes/planes/create-plan Crea un plan de cobro recurrente (suscripción) en Tilopay con su título, moneda, frecuencia y modalidades (nombre y monto). Devuelve el ID del plan creado; luego usa tilopay_recurring_subscription_url para obtener el enlace con el que los clientes se suscriben. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `title` | string | sí | Título del plan | | `modality` | array | sí | Modalidades del plan (mínimo 1): arreglo de { title: string, amount: number > 0 }. El monto recurrente es el de la primera modalidad. Ejemplo: [{"title": "Mensual", "amount": 10}] | | `frequency` | string (diario | semanal | mensual | anual | quincenal | bimestral | trimestral | cuatrimestral | semestral) | sí | Frecuencia de cobro | | `description` | string | — | Descripción del plan | | `currency` | string | — | Moneda ISO 4217, ej. USD o CRC. Si se omite se usa la del país del comercio. | | `first_amount` | number | — | Monto del pago inicial (0 si no hay) | | `trial_days` | integer | — | Días de prueba gratis (0 si no hay prueba) | | `attempts` | integer | — | Reintentos ante un cobro fallido (1 por defecto) | | `end_at` | string | — | Fecha de fin del plan en formato DD-MM-YYYY (opcional) | | `thanks_url` | string | — | URL de agradecimiento tras suscribirse (opcional) | | `webhook_subscribe` | string | — | Webhook al suscribirse un cliente (opcional) | | `webhook_payment` | string | — | Webhook al cobrarse un pago (opcional) | | `webhook_rejected` | string | — | Webhook al rechazarse un cobro (opcional) | | `webhook_unsubscribe` | string | — | Webhook al cancelarse una suscripción (opcional) | | `webhook_reactive` | string | — | Webhook al reactivarse una suscripción (opcional) | **Devuelve** `{ result, currency, frequency }` result = respuesta del API con el plan creado; currency y frequency = la moneda y la frecuencia con la que quedó el plan. ### Editar plan de suscripción [#tilopay-recurring-edit-plan] - `tilopay_recurring_edit_plan` - Acceso: Escritura - Operación del API: `POST /api/v1/editPlanRepeat` — https://tilopay.com/developers/api/recurrentes/planes/edit-plan Modifica un plan existente; no es edición parcial. title y frequency son obligatorios. Los campos omitidos se envían con sus valores por defecto: descripción vacía, first_amount 0, sin prueba gratis, attempts 1, webhooks y URL de agradecimiento vacíos; status omitido se envía como 1 (activo). El agente debe leer el plan con tilopay_recurring_get_plan y reenviar todos los campos. modality es opcional; si se omite se conserva el precio. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `id` | string | sí | ID del plan | | `title` | string | sí | Título del plan | | `frequency` | string (diario | semanal | mensual | anual | quincenal | bimestral | trimestral | cuatrimestral | semestral) | sí | Frecuencia de cobro | | `modality` | array | — | Arreglo opcional de {title: string (máximo 60 caracteres), amount: number > 0}; omitido conserva el precio. | | `currency` | string | — | Moneda ISO 4217 | | `description` | string | — | Descripción del plan; omitida se envía vacía. | | `first_amount` | number | — | Pago inicial; omitido se envía 0. | | `trial_days` | integer | — | Días de prueba gratis; omitido se envía sin prueba gratis. | | `attempts` | integer | — | Reintentos; omitido se envía 1. | | `status` | string (inactive | active | closed_to_new) | — | Estado: inactive, active o closed_to_new; omitido se envía 1 (activo). | | `end_at` | string | — | Fecha de fin del plan en formato DD-MM-YYYY (opcional) | | `thanks_url` | string | — | URL de agradecimiento; omitida se envía vacía. | | `webhook_subscribe` | string | — | Webhook al suscribirse; omitido se envía vacío. | | `webhook_payment` | string | — | Webhook al cobrarse un pago; omitido se envía vacío. | | `webhook_rejected` | string | — | Webhook al rechazarse un cobro; omitido se envía vacío. | | `webhook_unsubscribe` | string | — | Webhook al cancelarse; omitido se envía vacío. | | `webhook_reactive` | string | — | Webhook al reactivarse; omitido se envía vacío. | **Devuelve** `{ result }` result = respuesta del API al editar el plan; los campos omitidos se envían con sus valores por defecto, excepto modality, que conserva el precio. ### Eliminar plan de suscripción [#tilopay-recurring-delete-plan] - `tilopay_recurring_delete_plan` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones - Operación del API: `POST /api/v1/deletePlanRepeat` — https://tilopay.com/developers/api/recurrentes/planes/delete-plan Elimina un plan de cobro recurrente en Tilopay. Afecta los cobros futuros del plan: confirma con el comercio antes de ejecutarla. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `id` | string | sí | ID del plan | **Devuelve** `{ result }` result = respuesta del API al eliminar el plan. Los suscriptores del plan dejan de cobrarse. ### Enlace de suscripción a un plan [#tilopay-recurring-subscription-url] - `tilopay_recurring_subscription_url` - Acceso: Sólo lectura - Operación del API: `POST /api/v1/recurrentUrl` — https://tilopay.com/developers/api/recurrentes/suscriptores/consult-url Devuelve el enlace con el que un cliente se registra en un plan recurrente (o lo renueva si el correo ya está suscrito). Entregue la URL completa, sin recortarla. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `id` | string | sí | ID del plan | | `email` | string | — | Correo del cliente; si ya está suscrito devuelve el enlace de renovación | **Devuelve** `{ url, result }` url = enlace de suscripción al plan, para compartir con el cliente; result = respuesta del API tal cual. ### Editar suscriptor de un plan [#tilopay-recurring-edit-subscriber] - `tilopay_recurring_edit_subscriber` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones - Operación del API: `POST /api/v1/editSuscriptorRepeat` — https://tilopay.com/developers/api/recurrentes/suscriptores/edit-suscriptor-plan Cambia status (active, paused o deleted), expire (YYYY-MM-DD), modality (ID de la modalidad), amount (mayor que 0) y planId de un suscriptor; sólo envía los campos presentes. Si planId falta, se busca. La pueden usar el dueño y los empleados. No exige código por correo: para pausar, reactivar o eliminar con segundo factor existe tilopay_recurring_manage_subscriber. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `id` | string | sí | ID del suscriptor | | `status` | string (active | paused | deleted) | — | Nuevo estado del suscriptor | | `expire` | string | — | Fecha de expiración del plan para ese suscriptor en formato YYYY-MM-DD | | `modality` | string | — | ID de la modalidad. | | `amount` | number | — | Monto mayor que 0. | | `planId` | string | — | ID del plan; si falta se busca. | **Devuelve** `{ result }` result = respuesta del API al editar los campos presentes del suscriptor. ### Crear cupón de descuento [#tilopay-recurring-create-coupon] - `tilopay_recurring_create_coupon` - Acceso: Escritura - Operación del API: `POST /api/v1/createCoupon` — https://tilopay.com/developers/api/recurrentes/cupones/create-coupon Crea un cupón de descuento para un plan de suscripción: porcentaje o monto fijo, fecha de vencimiento, correos permitidos y límites de uso. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `planId` | string | sí | ID del plan recurrente | | `discount_type` | string (percentage | fixed) | sí | Tipo de descuento: percentage (porcentaje) o fixed (monto fijo) | | `discount` | number | sí | Valor del descuento | | `expire` | string | sí | Fecha de vencimiento del cupón en formato YYYY-MM-DD | | `allow_existing_users` | boolean | — | true si también lo pueden usar clientes ya registrados (false = solo nuevos) | | `emails` | array | — | Correos autorizados; si se omite, cualquier correo puede usarlo | | `usage` | integer | — | Cantidad total de usos | | `renews` | integer | — | Renovaciones válidas con el cupón | | `renews_by_user` | integer | — | Usos por un mismo cliente | **Devuelve** `{ result }` result = respuesta del API con el cupón de descuento creado para el plan. ### Cupones de un plan [#tilopay-recurring-list-coupons] - `tilopay_recurring_list_coupons` - Acceso: Sólo lectura - Operación del API: `POST /api/v1/getRepeatCoupons` — https://tilopay.com/developers/api/recurrentes/cupones/get-coupons Lista los cupones de descuento asociados a un plan de suscripción. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `planId` | string | sí | ID del plan recurrente | **Devuelve** `{ result }` result = cupones del plan tal cual los devuelve el API. ### Detalle de un cupón [#tilopay-recurring-get-coupon] - `tilopay_recurring_get_coupon` - Acceso: Sólo lectura - Operación del API: `POST /api/v1/getCoupon` — https://tilopay.com/developers/api/recurrentes/cupones/get-coupon Obtiene el detalle de un cupón de descuento por su ID. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `id` | string | sí | ID del cupón | **Devuelve** `{ result }` result = detalle de un cupón tal cual lo devuelve el API. ### Eliminar un cupón [#tilopay-recurring-delete-coupon] - `tilopay_recurring_delete_coupon` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones - Operación del API: `POST /api/v1/deleteCoupon` — https://tilopay.com/developers/api/recurrentes/cupones/delete-coupon Elimina un cupón de descuento de un plan de suscripción. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `id` | string | sí | ID del cupón | **Devuelve** `{ result }` result = respuesta del API al eliminar el cupón. ### Iniciar paso a paso de un plan de suscripción [#tilopay-recurring-plan-wizard-start] - `tilopay_recurring_plan_wizard_start` - Acceso: Escritura Inicia el paso a paso guiado para crear (mode=create) o editar (mode=edit con plan_id) un plan de suscripción. Devuelve la primera pregunta pendiente: entréguela al comercio tal cual y pase su respuesta a tilopay_recurring_plan_wizard_answer. Úselo en vez de tilopay_recurring_create_plan cuando falte algún dato. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `mode` | string (create | edit) | sí | create para un plan nuevo, edit para modificar uno existente | | `plan_id` | string | — | ID del plan (obligatorio en mode=edit) | | `title` | string | — | Título, si el comercio ya lo dijo | | `frequency` | string (diario | semanal | quincenal | mensual | bimestral | trimestral | cuatrimestral | semestral | anual) | — | Frecuencia, si el comercio ya la dijo | | `amount` | number | — | Monto por ciclo, si el comercio ya lo dijo | | `currency` | string | — | Moneda ISO si el comercio la indicó con símbolo o nombre ($ o dólares = USD, ₡ o colones = CRC) | | `description` | string | — | Descripción, si ya la dijo | **Devuelve** `{ draft }` draft = borrador del plan en proceso, con lo que ya se respondió y el siguiente paso pendiente. No crea nada en Tilopay hasta confirmar. ### Responder un paso del plan de suscripción [#tilopay-recurring-plan-wizard-answer] - `tilopay_recurring_plan_wizard_answer` - Acceso: Escritura Guarda la respuesta del comercio al paso actual del plan de suscripción y devuelve la siguiente pregunta o el resumen para confirmar. Entregue el texto devuelto tal cual, sin agregar preguntas propias. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `answer` | string | sí | Lo que respondió el comercio, tal cual | **Devuelve** `{ draft }` draft = el borrador actualizado con la respuesta del paso y el siguiente paso pendiente. ### Confirmar el plan de suscripción [#tilopay-recurring-plan-wizard-confirm] - `tilopay_recurring_plan_wizard_confirm` - Acceso: Escritura - Operación del API: `POST /api/v1/createPlanRepeat` — https://tilopay.com/developers/api/recurrentes/planes/create-plan Crea o edita el plan de suscripción con los datos del paso a paso, después de que el comercio dijo sí al resumen. Al crear devuelve además el enlace de suscripción: entréguelo completo, sin recortarlo. **Parámetros** Sin parámetros. **Devuelve** `{ plan_id, subscription_url }` Crea el plan con lo que se armó paso a paso: plan_id = id del plan creado; subscription_url = enlace de suscripción para compartir. ### Cancelar el paso a paso del plan [#tilopay-recurring-plan-wizard-cancel] - `tilopay_recurring_plan_wizard_cancel` - Acceso: Escritura Descarta el plan de suscripción que estaba en proceso sin crear ni cambiar nada. **Parámetros** Sin parámetros. **Devuelve** Descarta el borrador del plan en proceso. No crea ni cambia nada en Tilopay; devuelve sólo la confirmación en texto. ### Enlace de pago para poner al día un cobro recurrente fallido [#tilopay-recurring-settle-link] - `tilopay_recurring_settle_link` - Acceso: Escritura - Operación del API: `POST /api/v1/createLinkPayment` — https://tilopay.com/developers/api/links-de-pago/create-link-payment Crea un enlace de pago por el monto de un cobro recurrente que falló y lo asocia al suscriptor del plan. Cuando el cliente paga ese enlace, la suscripción queda al día automáticamente: el suscriptor se reactiva y su fecha de expiración avanza al siguiente ciclo. Úsala cuando el comercio acepte enviarle el enlace al cliente de un cobro fallido (los datos salen de tilopay_recurring_failed_payments). Devuelve la URL del enlace y, si hay teléfono, un enlace de WhatsApp listo para enviarle al cliente. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `subscriber_id` | string | sí | ID del suscriptor con el cobro fallido | | `amount` | number | sí | Monto pendiente del cobro fallido | | `currency` | string | — | Moneda del cobro. Si se omite se usa la del país del comercio. | | `plan_id` | string | — | ID del plan de suscripción | | `plan_name` | string | — | Nombre del plan, para el concepto del cobro | | `frequency` | string (diario | semanal | quincenal | mensual | bimestral | trimestral | cuatrimestral | semestral | anual) | — | Frecuencia del plan; si se omite se consulta al plan o se asume mensual | | `client_name` | string | — | Nombre del cliente | | `client_email` | string | — | Correo del cliente | | `client_phone` | string | — | Teléfono del cliente en formato internacional, para el enlace de WhatsApp | | `message` | string | — | Mensaje propio para el cliente; si se omite se arma uno | **Devuelve** `{ url, linkId, whatsapp_url, currency, amount, subscriber_id, frequency }` Crea un enlace de pago de un solo uso para que el suscriptor ponga al día un cobro recurrente fallido: url = enlace de pago; whatsapp_url = enlace de WhatsApp listo para enviarlo; linkId = id del enlace creado. ### Enlaces para poner al día varios cobros fallidos [#tilopay-recurring-settle-batch] - `tilopay_recurring_settle_batch` - Acceso: Escritura Envío en tanda (máximo 20) de enlaces para poner al día cobros recurrentes fallidos. Primero llámala SIN confirmar: devuelve el resumen (cantidad, total, quiénes no tienen teléfono) y una huella. Muestra ese resumen TAL CUAL y pide un sí explícito. Solo si el comercio responde sí, llámala de nuevo con confirm=true y la MISMA huella. Úsala cuando pida «mandales a todos»; para un solo cliente usa tilopay_recurring_settle_link. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `confirm` | boolean | — | true solo tras el sí explícito al resumen | | `fingerprint` | string | — | Huella devuelta por el resumen | | `subscriber_ids` | array | — | Limitar a estos suscriptores; si se omite, todos los pendientes (máx. 20) | **Devuelve** `{ ok, preview, fingerprint, count } | { ok, created, count }` Vista previa: { ok, preview: true, fingerprint, count }. Ejecución (con confirm: true y la misma huella): { ok, created, count }. ### Poner al día un suscriptor [#tilopay-recurring-mark-settled] - `tilopay_recurring_mark_settled` - Acceso: Escritura - Operación del API: `POST /api/v1/editSuscriptorRepeat` — https://tilopay.com/developers/api/recurrentes/suscriptores/edit-suscriptor-plan Marca al suscriptor como al día en su plan: lo deja activo y corre su fecha de expiración al siguiente ciclo. Úsala cuando el cobro pendiente ya se pagó por otro medio. Si el pago se hizo con el enlace de tilopay_recurring_settle_link, no hace falta: se actualiza solo. Confirma con el comercio antes de ejecutarla. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `subscriber_id` | string | sí | ID del suscriptor | | `plan_id` | string | — | ID del plan de suscripción | | `frequency` | string (diario | semanal | quincenal | mensual | bimestral | trimestral | cuatrimestral | semestral | anual) | — | Frecuencia del plan; si se omite se consulta al plan o se asume mensual | | `expire` | string | — | Nueva fecha de expiración YYYY-MM-DD; si se omite se calcula el siguiente ciclo | **Devuelve** `{ ok, expire, frequency }` Corre la fecha de vencimiento del suscriptor según la frecuencia del plan, para dejarlo al día después de recuperar un cobro fallido. expire = la nueva fecha de vencimiento. --- # Tarjetas guardadas y cobros masivos > Herramientas del MCP para guardar la tarjeta de un cliente, cobrarle, eliminarla y trabajar con los grupos de cobro masivo. - kind: mcp-tool - status: stable - access: destructive - last_verified: 2026-10-20 - url: https://tilopay.com/developers/agentes/mcp/tarjetas-guardadas ## Qué cubre [#que-cubre] Este grupo trabaja con las tarjetas que los clientes del comercio ya autorizaron guardar (tokenización) y con los cobros masivos a esas tarjetas. Cómo funciona el guardado: el agente genera un **enlace seguro** y lo comparte con el cliente; el cliente digita ahí su tarjeta. Ni el agente, ni el modelo, ni el comercio ven el número completo: las herramientas de consulta devuelven la marca y los últimos dígitos. Las operaciones sensibles del grupo —cobrar a una tarjeta guardada, eliminar una tarjeta y crear cobros masivos— exigen un **código de confirmación** que llega al correo del comercio. [Referencia del API: Cobros con tarjetas guardadas](/developers/api/cobros-tarjetas-guardadas). ## Herramientas [#herramientas] ### Listar grupos de cobro [#tilopay-saved-cards-list-groups] - `tilopay_saved_cards_list_groups` - Acceso: Sólo lectura - Operación del API: `POST /api/v1/collect/get/groups` — https://tilopay.com/developers/api/cobros-tarjetas-guardadas/get-groups Lista los grupos de cobro con tarjetas almacenadas (afiliados) en Tilopay. **Parámetros** Sin parámetros. **Devuelve** `{ result }` Respuesta cruda del API de Tilopay bajo la llave `result`. ### Listar afiliados con tarjeta almacenada [#tilopay-saved-cards-list-affiliates] - `tilopay_saved_cards_list_affiliates` - Acceso: Sólo lectura - Operación del API: `POST /api/v1/collect/get/affiliates` — https://tilopay.com/developers/api/cobros-tarjetas-guardadas/get-affiliates Lista los afiliados (clientes con tarjeta almacenada) de un grupo de cobro. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `group` | integer | — | ID del grupo (entero opcional; 0 u omitido = todos) | **Devuelve** `{ result }` Respuesta cruda del API de Tilopay bajo la llave `result`. ### Listar cobros masivos [#tilopay-saved-cards-list-collections] - `tilopay_saved_cards_list_collections` - Acceso: Sólo lectura - Operación del API: `POST /api/v1/collect/get/massive` — https://tilopay.com/developers/api/cobros-tarjetas-guardadas/get-massive Lista los cobros masivos realizados con tarjetas almacenadas en Tilopay (los 50 más recientes). **Parámetros** Sin parámetros. **Devuelve** `{ result }` Respuesta cruda del API de Tilopay bajo la llave `result`. ### Detalle de un cobro masivo [#tilopay-saved-cards-collection-detail] - `tilopay_saved_cards_collection_detail` - Acceso: Sólo lectura - Operación del API: `POST /api/v1/collect/get/massive/detail` — https://tilopay.com/developers/api/cobros-tarjetas-guardadas/get-massive-detail Obtiene el detalle de un cobro masivo. Requiere el `code` del cobro (campo `code` devuelto por tilopay_saved_cards_list_collections). **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `code` | string | sí | El campo code del listado de cobros (obligatorio) | **Devuelve** `{ result }` Respuesta cruda del API de Tilopay bajo la llave `result`. ### Guardar la tarjeta de un cliente (tokenizar) [#tilopay-tokenize-card] - `tilopay_tokenize_card` - Acceso: Escritura - Operación del API: `POST /api/v1/processTokenize` — https://tilopay.com/developers/api/cof/process-tokenize Genera el enlace seguro de Tilopay donde el cliente ingresa su tarjeta para dejarla guardada (tokenizada). El comercio nunca ve ni recibe los datos de la tarjeta. Una vez guardada, se le puede cobrar con tilopay_saved_cards_create_payments (esa sí pide código de confirmación por correo). Si se indica un contacto o teléfono, también devuelve un enlace de WhatsApp con el mensaje listo para enviarle al cliente. Además de los cobros masivos con tilopay_saved_cards_create_payments, una tarjeta guardada se cobra individual con tilopay_charge_saved_card. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `email` | string | sí | Correo del tarjetahabiente | | `first_name` | string | sí | Nombre del tarjetahabiente | | `last_name` | string | sí | Apellido del tarjetahabiente | | `language` | string (es | en) | — | Idioma del formulario (es por defecto) | | `redirect_url` | string | — | URL a la que vuelve el cliente al terminar (opcional) | | `contact_name` | string | — | Nombre del contacto guardado o del cliente, para armar el mensaje de WhatsApp | | `phone` | string | — | Teléfono de WhatsApp del cliente, ej. +50688887777 | | `message` | string | — | Texto propio para el mensaje al cliente | | `save_contact` | boolean | — | Guardar el contacto en la agenda | **Devuelve** `{ tokenize_url, whatsapp_url, email, contact }` tokenize_url = enlace seguro donde el cliente ingresa su tarjeta para guardarla; whatsapp_url = enlace de WhatsApp listo para enviárselo. La tarjeta la digita el cliente: el agente nunca recibe el número. ### Listar las tarjetas guardadas de un cliente [#tilopay-list-customer-cards] - `tilopay_list_customer_cards` - Acceso: Sólo lectura Lista las tarjetas que un cliente ya tiene guardadas (tokenizadas) en Tilopay, identificadas por el correo del cliente. Devuelve el token de cada tarjeta, que es lo que necesita tilopay_charge_saved_card para cobrarle. Solo se pueden cobrar tarjetas guardadas con el enlace de este asistente o del MCP. No cobra nada. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `email` | string | sí | Correo del cliente dueño de las tarjetas | | `currency` | string | — | Moneda de referencia, ej. CRC o USD. Si se omite se usa la del país del comercio. | **Devuelve** `{ cards, count }` cards = tarjetas ya guardadas de ese cliente, con marca, últimos dígitos y su identificador para cobrar; count = cuántas hay. Nunca devuelve el número completo de la tarjeta. ### Métodos de pago disponibles y cuotas [#tilopay-payment-methods] - `tilopay_payment_methods` - Acceso: Sólo lectura Lista los métodos de pago habilitados para el comercio en el checkout de Tilopay (tarjetas, SINPE Móvil, Yappy, cuotas o tasa cero cuando están activos) y si la cuenta responde en producción o en pruebas. Úsala cuando el comercio pregunte qué puede ofrecerle a su cliente o si tiene cuotas / tasa cero. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `amount` | number | — | Monto de referencia; algunos métodos y cuotas dependen del monto | | `currency` | string | — | Moneda de referencia. Si se omite se usa la del país del comercio. | | `email` | string | — | Correo del cliente (opcional; solo para ver también las tarjetas guardadas de ese cliente) | **Devuelve** `{ methods, installments, cards, environment, currency }` methods = métodos de pago habilitados para el comercio; installments = cuotas disponibles cuando el método las admite; cards = tarjetas guardadas del cliente si se envió su correo; environment = production o test. ### Cobrar a una tarjeta guardada de un cliente [#tilopay-charge-saved-card] - `tilopay_charge_saved_card` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones - Operación del API: `POST /api/v1/processRecurrentPayment` — https://tilopay.com/developers/api/cof/realizar-cobro Cobra un monto a una tarjeta ya guardada (tokenizada) de un cliente. Requiere el correo del cliente y el token de la tarjeta (se obtiene con tilopay_list_customer_cards). Operación sensible: mueve dinero real y requiere segundo factor. Llámela primero sin `confirmation_code`: se envía un código de 6 dígitos al correo del comercio y la respuesta trae `requires_confirmation`. Repita la misma llamada, con los mismos parámetros, agregando `confirmation_code`. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `email` | string | sí | Correo del tarjetahabiente | | `card` | string | sí | Token de la tarjeta guardada (versión v2) | | `amount` | number | sí | Monto a cobrar | | `currency` | string | — | Moneda del cobro. Si se omite se usa la del país del comercio. | | `order_number` | string | — | Número de orden; si se omite se genera uno único | | `capture` | boolean | — | Capturar de inmediato (por defecto true) | | `confirmation_code` | string | — | Código de 6 dígitos recibido por correo para autorizar la operación | **Devuelve** `{ result, approved, orderNumber, currency, receipt_code, receipt_url, receipt_image_url }` Cobra a una tarjeta ya guardada del cliente: approved = si el cobro fue aprobado; orderNumber = número de orden generado; receipt_* = comprobante del cobro cuando se generó. Exige segundo factor por correo. ### Eliminar una tarjeta guardada de un cliente [#tilopay-remove-saved-card] - `tilopay_remove_saved_card` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones - Operación del API: `POST /api/v1/user/card-remove` — https://tilopay.com/developers/api/cof/remove-card Elimina una tarjeta guardada (token) de un cliente en Tilopay. Operación sensible: requiere segundo factor. Llámela primero sin `confirmation_code` y repítala luego con el código de 6 dígitos que llega al correo del comercio. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `email` | string | sí | Correo del cliente dueño de la tarjeta | | `token` | string | sí | Token de la tarjeta a eliminar | | `confirmation_code` | string | — | Código de 6 dígitos recibido por correo para autorizar la operación | **Devuelve** `{ result }` result = respuesta del API al eliminar la tarjeta guardada del cliente. Exige segundo factor por correo. ### Cobrar a tarjetas almacenadas [#tilopay-saved-cards-create-payments] - `tilopay_saved_cards_create_payments` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones - Operación del API: `POST /api/v1/collect/set/payments` — https://tilopay.com/developers/api/cobros-tarjetas-guardadas/set-payments Crea cobros a afiliados y/o grupos con tarjetas almacenadas en Tilopay (sólo el dueño; exige el código de confirmación que llega al correo). Sólo se puede cobrar a afiliados cuyas tarjetas se guardaron con tilopay_tokenize_card; en un grupo, todos sus miembros deben cumplirlo. Sin idempotencia: repetir la operación con un código nuevo cobra otra vez. currency y capture se muestran en el correo de autorización pero hoy no se envían en el cobro. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `reason` | string | sí | Motivo del cobro, ej. "Cobro mensualidad" | | `capture` | boolean | — | Se muestra en el correo de autorización, pero hoy no se envía en el cobro. | | `users` | array | — | Arreglo de { id: string, amount: number > 0, currency: string, date?: "YYYY-MM-DD" }; date programa el cobro currency se muestra en el correo de autorización pero hoy no se envía en el cobro. | | `groups` | array | — | Arreglo de { id: string, amount: number > 0 (monto por afiliado), currency: string, date?: "YYYY-MM-DD" } currency se muestra en el correo de autorización pero hoy no se envía en el cobro. | | `confirmation_code` | string | — | Código de 6 dígitos recibido por correo para autorizar la operación | **Devuelve** `{ result }` result = respuesta del API de Tilopay (o results[] si hubo varias llamadas). --- # Liquidaciones, depósitos y facturación > Herramientas del MCP para consultar la próxima liquidación, el historial de liquidaciones, los depósitos de garantía y las facturas que Tilopay le emite al comercio. - kind: mcp-tool - status: stable - access: write - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/mcp/liquidaciones ## Qué cubre [#que-cubre] Este grupo cubre el dinero que Tilopay le liquida al comercio: el balance por liquidar y la fecha del próximo depósito, las liquidaciones ya procesadas con sus transacciones, los depósitos de garantía (preautorizaciones retenidas a clientes) y las facturas que Tilopay emite por el uso de la plataforma. Todo es de lectura salvo extender un depósito de garantía, que exige un código de seis dígitos que llega por correo. ## Herramientas [#herramientas] ### Próxima liquidación y balance por liquidar [#tilopay-settlement-balance] - `tilopay_settlement_balance` - Acceso: Sólo lectura Dato OFICIAL de Tilopay: fecha del próximo depósito (next_settlement), frecuencia de liquidación, cuenta IBAN destino y, por moneda, el balance acumulado pendiente con su desglose (subtotal, commission, iva_commission, retention, retention_iva, cost, iva_tilopay, transfer, transfer_iva, total neto). Úsala para «¿cuándo me depositan?», «¿cuánto me van a liquidar?», «¿cuánto me cobran de comisión?». **Parámetros** Sin parámetros. **Devuelve** `{ next_settlement, commerce, accumulated_balance, accumulated_balance_details }` next_settlement = próxima liquidación; commerce = datos del comercio con el IBAN enmascarado; accumulated_balance = [{ total, currency }]; accumulated_balance_details = el detalle. ### Historial de liquidaciones [#tilopay-settlements-list] - `tilopay_settlements_list` - Acceso: Sólo lectura Liquidaciones ya procesadas por Tilopay: fecha de depósito (date_to_report), periodo, monto bruto, deducciones y total transferido. Úsala para «¿ya me depositaron lo del viernes?» o «¿cuánto me depositaron el mes pasado?». **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `page` | integer | — | Página (por defecto 1) | | `limit` | integer | — | Registros por página (por defecto 20) | | `search` | string | — | Texto a buscar | **Devuelve** ### Transacciones de una liquidación [#tilopay-settlement-transactions] - `tilopay_settlement_transactions` - Acceso: Sólo lectura Transacciones incluidas en una liquidación ya procesada (id obtenido de tilopay_settlements_list). **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `settlement_id` | string | sí | Id de la liquidación | **Devuelve** ### Depósitos de garantía (preautorizaciones) [#tilopay-deposits-list] - `tilopay_deposits_list` - Acceso: Sólo lectura Depósitos de garantía o preautorizaciones retenidas a clientes (renta de autos, hotelería, depósitos de seguridad): monto, estado y vencimiento. No confundir con liquidaciones. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `page` | integer | — | Página (por defecto 1) | | `limit` | integer | — | Registros por página (por defecto 20) | | `search` | string | — | Texto a buscar | **Devuelve** ### Detalle de un depósito de garantía [#tilopay-deposit-detail] - `tilopay_deposit_detail` - Acceso: Sólo lectura Detalle de un depósito de garantía (id de tilopay_deposits_list). **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `deposit_id` | string | sí | Id del depósito | **Devuelve** ### Extender un depósito de garantía [#tilopay-deposit-extend] - `tilopay_deposit_extend` - Acceso: Escritura Extiende la vigencia de la autorización de un depósito de garantía, sólo el dueño. Exige el código de 6 dígitos por correo, pero confirmation_code no está declarado en el esquema: el flujo de dos llamadas se completa desde el Asistente de WhatsApp. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `deposit_id` | string | sí | Id del depósito | **Devuelve** Tras autorizar, devuelve los datos de la extensión que entrega Tilopay. ### Facturas del servicio Tilopay [#tilopay-billing-list] - `tilopay_billing_list` - Acceso: Sólo lectura Facturas que Tilopay le emite al comercio por el uso de la plataforma (no son ventas del comercio). Úsala para «¿cuánto me cobró Tilopay este mes?» o «¿dónde está mi factura de Tilopay?». **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `page` | integer | — | Página (por defecto 1) | | `limit` | integer | — | Registros por página (por defecto 20) | | `search` | string | — | Texto a buscar | **Devuelve** --- # Cuenta, comercio y equipo > Herramientas del MCP para vincular o desvincular la cuenta, elegir el comercio activo, gestionar empleados del asistente y consultar usuarios del panel y métodos de pago habilitados. - kind: mcp-tool - status: stable - access: destructive - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/mcp/cuenta ## Qué cubre [#que-cubre] Este grupo cubre la cuenta de Tilopay vinculada al asistente: vincularla o desvincularla, elegir el comercio activo cuando hay varios, dar o quitar acceso a empleados, y consultar los usuarios del panel web y los métodos de pago y monedas habilitados. Desvincular la cuenta y quitar el acceso a un empleado están marcadas como sensibles y piden confirmación explícita antes de ejecutarse. ## Herramientas [#herramientas] ### Comercio seleccionado [#tilopay-switch-commerce] - `tilopay_switch_commerce` - Acceso: Escritura Muestra el comercio activo de la cuenta de Tilopay vinculada y permite cambiarlo cuando la cuenta tiene varios. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `commerce_id` | string | — | Comercio que se quiere activar. Si se omite, solo se muestra el actual. | **Devuelve** `{ selected, selected_name, commerces }` selected = id del comercio activo; selected_name = su nombre; commerces = [{ id, name }] disponibles. ### Desvincular mi cuenta [#tilopay-unlink-account] - `tilopay_unlink_account` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones Desvincula la cuenta de Tilopay del asistente: revoca TODO el acceso (WhatsApp, Claude y otras aplicaciones), borra las claves guardadas (incluidas las del banco) y cierra las sesiones bancarias. Antes de llamarla con confirm=true, repítele al comercio ese alcance y pide confirmación. Úsela cuando el comercio pida desvincular, desconectar o quitar tu cuenta del asistente. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `confirm` | boolean | sí | Debe ser true: el comercio confirmó que quiere desvincular la cuenta | | `all_channels` | boolean | — | true solo si el comercio pidió expresamente desvincular también el otro canal (WhatsApp y clientes MCP). | **Devuelve** `{ unlinked, message }` unlinked = true cuando la cuenta quedó desvinculada. ### Vincular mi cuenta [#tilopay-send-link-flow] - `tilopay_send_link_flow` - Acceso: Escritura Envía al WhatsApp del comercio el botón para vincular (o volver a vincular) la cuenta de Tilopay con el asistente (solo en el Asistente de WhatsApp). Sirve ante cualquier petición de vincular, conectar o activar el asistente con la cuenta de Tilopay. **Parámetros** Sin parámetros. **Devuelve** ### Dar acceso a un empleado [#tilopay-invite-employee] - `tilopay_invite_employee` - Acceso: Escritura Invita a un empleado a usar el asistente con su propio usuario de Tilopay (solo el dueño). Pide nombre y teléfono de WhatsApp del empleado. Devuelve un enlace wa.me para que el dueño le envíe la invitación. En tu respuesta, repite primero la línea `prerequisito` tal cual y luego entrega el enlace. El empleado puede consultar ventas, crear cobros y enviar comprobantes; no puede reembolsar, cobrar tarjetas guardadas, crear o borrar productos, cambiar precios ni cambiar la configuración. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `name` | string | sí | Nombre del empleado | | `phone` | string | sí | WhatsApp del empleado, ej. 8888-8888 | **Devuelve** `{ prerequisito, invite_id, expires_at, whatsapp_url }` prerequisito = línea que el agente debe repetir: el empleado necesita su propio usuario de Tilopay creado en admin.tilopay.com › Usuarios; la invitación vence en 72 h. ### Ver mis empleados [#tilopay-list-employees] - `tilopay_list_employees` - Acceso: Sólo lectura Lista los empleados con acceso al asistente y las invitaciones pendientes (solo el dueño). **Parámetros** Sin parámetros. **Devuelve** `{ employees }` employees = [{ name, phone, status }]; el teléfono viene enmascarado y status es "activo" o "invitado". ### Quitar acceso a un empleado [#tilopay-remove-employee] - `tilopay_remove_employee` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones Quita el acceso de un empleado al asistente (solo el dueño): revoca toda su sesión, o cancela la invitación si no se había vinculado. Antes de llamarla con confirm=true, confirma con el dueño a quién se quita. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `name` | string | — | Nombre del empleado | | `phone` | string | — | Teléfono del empleado | | `confirm` | boolean | sí | true: el dueño confirmó quitarle el acceso | **Devuelve** `{ removed }` removed = empleados a los que se les quitó el acceso. ### Métodos de pago y monedas habilitados [#tilopay-accepted-payment-methods] - `tilopay_accepted_payment_methods` - Acceso: Sólo lectura Métodos de pago que el comercio tiene habilitados en Tilopay (marcas de tarjeta, SINPE, etc.), monedas configuradas y configuración PayFac. Úsala para «¿qué tarjetas acepto?», «¿tengo SINPE activo?», «¿puedo cobrar en dólares?». **Parámetros** Sin parámetros. **Devuelve** `{ methods, currencies, payfac }` methods = métodos de pago aceptados; currencies = monedas; payfac = configuración PayFac. ### Usuarios del panel de Tilopay [#tilopay-panel-users] - `tilopay_panel_users` - Acceso: Sólo lectura Usuarios que tienen acceso al panel web de Tilopay del comercio y sus módulos. Distinto de los empleados del asistente (tilopay_list_employees). **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `page` | integer | — | Página (por defecto 1) | | `limit` | integer | — | Registros por página (por defecto 20) | | `search` | string | — | Texto a buscar | **Devuelve** --- # Soporte y diagnóstico > Herramientas del MCP para responder con las guías oficiales y probar la conexión con el API. - kind: mcp-tool - status: stable - access: read - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/mcp/soporte ## Qué cubre [#que-cubre] Tres herramientas de lectura: una responde preguntas de uso del panel con las guías oficiales de tilopay.com/guias, otra prueba las credenciales y un endpoint de cada grupo del API para saber qué parte responde cuando algo falla, y la tercera analiza un fragmento de código o un stack trace que le pases y devuelve diagnóstico, causa raíz, corrección y riesgos. Esa última no lee repositorios ni ejecuta código. ## Herramientas [#herramientas] ### Diagnóstico de conexión con Tilopay [#tilopay-diagnostics] - `tilopay_diagnostics` - Acceso: Sólo lectura Verifica las credenciales del usuario y prueba un endpoint de cada grupo (ventas/transacciones, catálogo, recurrentes, tarjetas almacenadas). Úsalo cuando una herramienta falle para saber qué parte del API responde. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `environment` | string (production | test) | — | Ambiente para la prueba de transacciones (por defecto production) | **Devuelve** `{ checks, failed }` checks es una lista con check, ok y detail por cada prueba: credenciales, transacciones, catálogo, recurrentes y tarjetas almacenadas. failed es la cantidad de pruebas con error. Las credenciales se devuelven enmascaradas. ### Ayuda con las guías y tutoriales de Tilopay [#tilopay-help-guides] - `tilopay_help_guides` - Acceso: Sólo lectura Responde dudas de uso del panel de Tilopay (links de pago, catálogo, suscripciones, depósitos de garantía, reembolsos, API/SDK) usando las guías oficiales de tilopay.com/guias. Devuelve extractos y los enlaces a las guías. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `question` | string | sí | Pregunta del comercio, tal como la escribió | **Devuelve** `{ articles }` Hasta 3 artículos con title, url y excerpt, tomados de tilopay.com/guias. Si no hay coincidencia devuelve articles vacío y un texto con las guías disponibles. ### Depurar código [#tilopay-debug-code] - `tilopay_debug_code` - Acceso: Sólo lectura Analiza un fragmento de código o stack trace que envía el usuario y devuelve diagnóstico, causa raíz, corrección concreta y riesgos. No lee repositorios ni ejecuta código. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `code` | string | sí | Fragmento de código, log o stack trace tal como lo envió el usuario | | `error` | string | — | Mensaje de error o comportamiento observado, si lo hay | | `language` | string | — | Lenguaje o stack (ej. typescript, php, react). Si no se indica, se detecta | | `context` | string | — | Qué debería hacer el código o en qué momento falla | **Devuelve** `{ report, truncated, redacted, model }` report es el diagnóstico en texto (diagnóstico, causa raíz, corrección y riesgos). truncated indica si el código se recortó a 12.000 caracteres; redacted, si se ocultaron posibles credenciales antes del análisis; model, el modelo usado. No lee repositorios ni ejecuta el código. --- # Herramientas bancarias > Herramientas MCP para consultar cuentas, saldos, pagos y estados de cuenta, y gestionar transferencias con autorización por correo. Se activan bajo solicitud y sólo con credenciales del API bancario. - kind: mcp-tool - status: stable - access: write - last_verified: 2026-10-22 - url: https://tilopay.com/developers/agentes/mcp/api-bancario > **Advertencia:** Estas herramientas no vienen activadas. Se habilitan bajo solicitud y sólo funcionan para > usuarios con credenciales del API bancario de Tilopay registradas por Tilopay del lado del > servidor. Con el acceso MCP estándar el grupo no aparece; y si la herramienta se invoca sin esas > credenciales, responde que no existen. Para pedirlo, escribinos desde > [contacto](/contacto) e indicá que necesitás el API bancario. ## Qué cubre [#que-cubre] Diecinueve herramientas sobre el [API bancario](/developers/api-bancario): contextos (assignments), diagnóstico de credenciales, cuentas, saldos, número de cuenta completo, pagos, estados de cuenta, un informe analítico de pagos, la validación de una cuenta destino, la transferencia con su autorización, cancelación y aviso de resultado, la aprobación en doble control y el cierre de la sesión bancaria. **Trece de las diecinueve sólo extraen información.** `baas_request_statement` genera un documento de consulta y no mueve dinero. `baas_send_transfer` crea la intención de una transferencia, sin ejecutar el pago. El portal Banca Cliente envía un código de autorización al correo del comercio y `baas_confirm_transfer` ejecuta la transferencia con ese código. Si la operación queda en doble control, el aprobador la decide con `banca_decide_approval` y un código que llega a su correo. Así, no puede ejecutarse por decisión del modelo. La cuenta propia se elige por precedencia: `accountValue` (sólo si coincide con una cuenta del usuario) → `currency` (primera cuenta en esa moneda) → `accountIndex` (base 1: el número que muestra `baas_list_accounts`) → si hay una sola cuenta, esa. `baas_get_account_number` acepta sólo `currency` o `accountIndex`. Las fechas son RFC 3339 (`2026-01-01T00:00:00Z`) y `assignmentId` se envía únicamente cuando el usuario tiene varios contextos. ## Herramientas [#herramientas] El flujo de autorización por correo y doble control descrito aquí corresponde al MCP y Banca Cliente. La creación directa de pagos en el [API Bancario](/developers/api-bancario/pagos#procesamiento) no tiene doble control: procesa el pago si el token, los permisos y los datos son válidos. Los estados de cuenta se generan de forma asíncrona: el API responde `202 ACCEPTED` con `request_id` y `PENDING`. La consulta responde `200` con `PENDING`, `PROCESSING`, `DONE` o `ERROR`; en `DONE`, `download_url` es válida por **48 horas**. > Estas herramientas se activan bajo solicitud y sólo funcionan para usuarios con credenciales del API bancario de Tilopay. No forman parte del acceso MCP por defecto: Tilopay habilita el grupo caso por caso. Requiere: Credenciales del API bancario de Tilopay registradas por Tilopay para ese usuario. - [Otras operaciones](https://tilopay.com/developers/agentes/mcp/api-bancario/otras-operaciones) — `baas_list_assignments`, `baas_diagnostics`, `baas_list_accounts`, `baas_get_balance`, `baas_get_account_number`, `baas_get_statement_status`, `baas_cancel_transfer`, `banca_decide_approval`, `baas_close_session` (Sólo lectura / Sólo lectura / Sólo lectura / Sólo lectura / Sólo lectura / Sólo lectura / Escritura / Sensible / Escritura): Contextos (assignments), diagnóstico de credenciales, listado de cuentas, saldo de una cuenta, número de cuenta completo, estado de una solicitud de estado de cuenta, cancelación de la transferencia pendiente, aprobación en doble control y cierre de la sesión bancaria. - [Saldos de las cuentas BaaS](https://tilopay.com/developers/agentes/mcp/api-bancario/list-balances) — `baas_list_balances` (Sólo lectura): Lista los saldos en tiempo real de las cuentas accesibles del API BaaS (cuenta, montos y fecha de corte). - [Listar pagos BaaS](https://tilopay.com/developers/agentes/mcp/api-bancario/list-payments) — `baas_list_payments` (Sólo lectura): Consulta (solo lectura) los movimientos/pagos de una cuenta bancaria propia. Indica la moneda (CRC/USD) o el número de cuenta de la lista: no escribe el IBAN. Filtros de fecha, estado, moneda, método y dirección, con paginación por cursor. - [Buscar un pago BaaS](https://tilopay.com/developers/agentes/mcp/api-bancario/search-payment) — `baas_search_payment` (Sólo lectura): Busca un pago BaaS dentro de una cuenta por exactamente uno de: paymentId (UUID), publicId (número) o clientReference. Identificadores solo de datos que una herramienta ya devolvió. - [Detalle de un pago BaaS](https://tilopay.com/developers/agentes/mcp/api-bancario/get-payment) — `baas_get_payment` (Sólo lectura): Obtiene el detalle de un pago BaaS por su UUID interno (solo lectura). Usa únicamente identificadores que otra herramienta devolvió en este mismo turno. - [Solicitar estado de cuenta BaaS](https://tilopay.com/developers/agentes/mcp/api-bancario/request-statement) — `baas_request_statement` (Escritura): Solicita la generación asíncrona de un estado de cuenta (rango máximo 60 días) para una cuenta BaaS. No mueve dinero: solo genera un documento de consulta. El API responde siempre 202 ACCEPTED con request_id y status PENDING. Consultá baas_get_statement_status para obtener la descarga; en DONE, download_url es válida por 48 horas. - [Analista de pagos BaaS](https://tilopay.com/developers/agentes/mcp/api-bancario/analyze-payments) — `baas_analyze_payments` (Sólo lectura): Analiza (solo lectura) los pagos BaaS de una cuenta en un rango de fechas y devuelve un informe en lenguaje natural: éxito, fallas, reversiones, montos netos y recomendaciones verificables. - [Validar cuenta destino BaaS](https://tilopay.com/developers/agentes/mcp/api-bancario/validate-destination) — `baas_validate_destination` (Sólo lectura): Valida una cuenta destino antes de transferir: PHONE para SINPE Móvil o IBAN para transferencia a cuenta. Devuelve el nombre del titular que el banco confirma. - [Enviar transferencia BaaS](https://tilopay.com/developers/agentes/mcp/api-bancario/send-transfer) — `baas_send_transfer` (Sensible): Crea la intención de una transferencia desde la cuenta bancaria del comercio en el portal Banca Cliente (todavía no es el pago). El portal valida el destino y envía un código de 6 dígitos al correo del comercio; el pago se ejecuta sólo cuando se llama baas_confirm_transfer con ese código (vigencia de 30 minutos). Método por defecto: SINPE Móvil (destino por teléfono); para transferencia a cuenta, destinationAccountType=IBAN. baas_validate_destination es opcional para mostrar el titular antes; esta herramienta valida el destino por su cuenta. - [Estado de transferencia BaaS](https://tilopay.com/developers/agentes/mcp/api-bancario/get-transfer-status) — `baas_get_transfer_status` (Sólo lectura): No consulta al banco: indica que el resultado de la transferencia llega como aviso en cuanto el banco lo confirma. paymentId es opcional y no se usa. - [Autorizar la transferencia pendiente](https://tilopay.com/developers/agentes/mcp/api-bancario/confirm-transfer) — `baas_confirm_transfer` (Sensible): Ejecuta la transferencia cuya intención creó baas_send_transfer, con el código de 6 dígitos que el portal Banca Cliente envió al correo del comercio. Nunca escribas ni repitas el código en la respuesta. --- # Saldos > Lista los saldos en tiempo real de las cuentas accesibles: cuenta, montos y fecha de corte. - kind: mcp-tool - status: stable - access: read - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/mcp/api-bancario/list-balances > Estas herramientas se activan bajo solicitud y sólo funcionan para usuarios con credenciales del API bancario de Tilopay. No forman parte del acceso MCP por defecto: Tilopay habilita el grupo caso por caso. Requiere: Credenciales del API bancario de Tilopay registradas por Tilopay para ese usuario. - `baas_list_balances` - Acceso: Sólo lectura - Operación del API: `GET /api/public/v1/accounts/balances` — https://tilopay.com/developers/api-bancario/cuentas Lista los saldos en tiempo real de las cuentas accesibles del API BaaS (cuenta, montos y fecha de corte). **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `accountType` | string | — | Filtro por esquema (IBAN) | | `accountValue` | string | — | Filtro por identificador | | `limit` | integer | — | 1–100, junto con offset | | `offset` | integer | — | Desplazamiento de paginación | | `assignmentId` | string | — | Contexto BaaS (opcional) | **Devuelve** `{ result }` result = respuesta del API bancario tal cual. --- # Pagos > Consulta los pagos de tu cuenta: accountValue válido → currency → accountIndex (base 1) → cuenta única. Filtros de fecha, estado, moneda, método y dirección; paginación por cursor. - kind: mcp-tool - status: stable - access: read - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/mcp/api-bancario/list-payments > Estas herramientas se activan bajo solicitud y sólo funcionan para usuarios con credenciales del API bancario de Tilopay. No forman parte del acceso MCP por defecto: Tilopay habilita el grupo caso por caso. Requiere: Credenciales del API bancario de Tilopay registradas por Tilopay para ese usuario. - `baas_list_payments` - Acceso: Sólo lectura - Operación del API: `GET /api/public/v1/transactions/payments` — https://tilopay.com/developers/api-bancario/pagos Consulta (solo lectura) los movimientos/pagos de una cuenta bancaria propia. Indica la moneda (CRC/USD) o el número de cuenta de la lista: no escribe el IBAN. Filtros de fecha, estado, moneda, método y dirección, con paginación por cursor. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `currency` | string | — | Moneda de la cuenta (CRC o USD): primera cuenta en esa moneda. Precedencia para elegir la cuenta propia: accountValue (sólo si coincide con una cuenta del usuario) → currency (primera cuenta en esa moneda) → accountIndex (base 1: el número que muestra baas_list_accounts) → si hay una sola cuenta, esa. | | `accountIndex` | integer | — | Número de la cuenta en la lista que muestra baas_list_accounts (base 1). Precedencia para elegir la cuenta propia: accountValue (sólo si coincide con una cuenta del usuario) → currency (primera cuenta en esa moneda) → accountIndex (base 1: el número que muestra baas_list_accounts) → si hay una sola cuenta, esa. | | `accountValue` | string | — | Sólo si una herramienta ya lo devolvió y coincide con una cuenta del usuario; no escribir números de cuenta de memoria. Precedencia para elegir la cuenta propia: accountValue (sólo si coincide con una cuenta del usuario) → currency (primera cuenta en esa moneda) → accountIndex (base 1: el número que muestra baas_list_accounts) → si hay una sola cuenta, esa. | | `assignmentId` | string | — | Contexto BaaS (opcional) | | `dateFrom` | string | — | Desde, RFC 3339 (2026-01-01T00:00:00Z) | | `dateTo` | string | — | Hasta, RFC 3339 | | `status` | string (pending | processing | confirmed | posted | failed) | — | Estado público del pago | | `paymentMethodCode` | string (PIN | SINPE_MOVIL) | — | "PIN" (transferencia a IBAN) o "SINPE_MOVIL" | | `direction` | string (OUT | IN) | — | OUT = envío, IN = recibido | | `clientReference` | string | — | Referencia del comercio | | `limit` | integer | — | Tamaño de página (máx 50) | | `cursor` | string | — | Cursor de la página anterior | **Devuelve** `{ result }` result = respuesta del API bancario tal cual, con su cursor de paginación. --- # Buscar un pago > Busca un pago dentro de una cuenta por exactamente uno de: paymentId (UUID), publicId (número) o clientReference. Si se envía más de uno, la herramienta devuelve error. - kind: mcp-tool - status: stable - access: read - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/mcp/api-bancario/search-payment > Estas herramientas se activan bajo solicitud y sólo funcionan para usuarios con credenciales del API bancario de Tilopay. No forman parte del acceso MCP por defecto: Tilopay habilita el grupo caso por caso. Requiere: Credenciales del API bancario de Tilopay registradas por Tilopay para ese usuario. - `baas_search_payment` - Acceso: Sólo lectura - Operación del API: `POST /api/public/v1/transactions/payments/search` — https://tilopay.com/developers/api-bancario/pagos Busca un pago BaaS dentro de una cuenta por exactamente uno de: paymentId (UUID), publicId (número) o clientReference. Identificadores solo de datos que una herramienta ya devolvió. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `currency` | string | — | Moneda de la cuenta a consultar (CRC o USD). Forma recomendada. | | `accountIndex` | integer | — | Número de la cuenta en la lista de cuentas del usuario | | `accountValue` | string | — | Solo si una herramienta ya lo devolvió. No escribe números de cuenta de memoria: indica la moneda (CRC/USD) o el número de la cuenta en la lista; el sistema resuelve el IBAN real. | | `assignmentId` | string | — | Contexto BaaS (opcional) | | `paymentId` | string | — | UUID interno del pago | | `publicId` | string | — | Identificador público numérico | | `clientReference` | string | — | Referencia del comercio | **Devuelve** `{ result }` result = respuesta del API bancario tal cual. --- # Detalle de un pago > Obtiene el detalle de un pago del API bancario por su UUID interno, sólo lectura. - kind: mcp-tool - status: stable - access: read - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/mcp/api-bancario/get-payment > Estas herramientas se activan bajo solicitud y sólo funcionan para usuarios con credenciales del API bancario de Tilopay. No forman parte del acceso MCP por defecto: Tilopay habilita el grupo caso por caso. Requiere: Credenciales del API bancario de Tilopay registradas por Tilopay para ese usuario. - `baas_get_payment` - Acceso: Sólo lectura - Operación del API: `GET /api/public/v1/transactions/payments/{payment_id}` — https://tilopay.com/developers/api-bancario/pagos Obtiene el detalle de un pago BaaS por su UUID interno (solo lectura). Usa únicamente identificadores que otra herramienta devolvió en este mismo turno. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `paymentId` | string | sí | UUID interno del pago | | `assignmentId` | string | — | Contexto BaaS (opcional) | **Devuelve** `{ result }` result = respuesta del API bancario tal cual. --- # Estado de cuenta > Solicita la generación de un estado de cuenta para una cuenta del API bancario, con rango máximo de 60 días. No mueve dinero: genera un documento de consulta y devuelve request_id con status PENDING. - kind: mcp-tool - status: stable - access: write - last_verified: 2026-10-22 - url: https://tilopay.com/developers/agentes/mcp/api-bancario/request-statement > Estas herramientas se activan bajo solicitud y sólo funcionan para usuarios con credenciales del API bancario de Tilopay. No forman parte del acceso MCP por defecto: Tilopay habilita el grupo caso por caso. Requiere: Credenciales del API bancario de Tilopay registradas por Tilopay para ese usuario. - `baas_request_statement` - Acceso: Escritura - Operación del API: `POST /api/public/v1/accounts/statements` — https://tilopay.com/developers/api-bancario/cuentas Solicita la generación asíncrona de un estado de cuenta (rango máximo 60 días) para una cuenta BaaS. No mueve dinero: solo genera un documento de consulta. El API responde siempre 202 ACCEPTED con request_id y status PENDING. Consultá baas_get_statement_status para obtener la descarga; en DONE, download_url es válida por 48 horas. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `currency` | string | — | Moneda de la cuenta (CRC o USD) | | `accountIndex` | integer | — | Número de la cuenta en la lista | | `accountValue` | string | — | Solo si una herramienta ya lo devolvió. No escribe números de cuenta de memoria: indica la moneda (CRC/USD) o el número de la cuenta en la lista; el sistema resuelve el IBAN real. | | `dateFrom` | string | sí | Desde, RFC 3339 (2026-01-01T00:00:00Z) | | `dateTo` | string | sí | Hasta, RFC 3339 (máx 60 días después) | | `assignmentId` | string | — | Contexto BaaS (opcional) | **Devuelve** `{ result }` result = respuesta del API bancario con request_id y status. La herramienta solicita el documento sin notificación por correo. ## Generación y descarga [#generacion] El API Bancario responde siempre `202 ACCEPTED` con `request_id` y `status: PENDING`; el documento se genera de forma asíncrona. Consultá su estado con `baas_get_statement_status`: el API responde `200` con `PENDING`, `PROCESSING`, `DONE` o `ERROR`. En `DONE` incluye `download_url`, válida por **48 horas**. --- # Analista de pagos > Analiza, sólo lectura, los pagos de una cuenta en un rango de fechas y devuelve un informe en lenguaje natural: éxito, fallas, reversiones, montos netos y recomendaciones. Usa un modelo de lenguaje sobre las cifras calculadas. - kind: mcp-tool - status: stable - access: read - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/mcp/api-bancario/analyze-payments > Estas herramientas se activan bajo solicitud y sólo funcionan para usuarios con credenciales del API bancario de Tilopay. No forman parte del acceso MCP por defecto: Tilopay habilita el grupo caso por caso. Requiere: Credenciales del API bancario de Tilopay registradas por Tilopay para ese usuario. - `baas_analyze_payments` - Acceso: Sólo lectura Analiza (solo lectura) los pagos BaaS de una cuenta en un rango de fechas y devuelve un informe en lenguaje natural: éxito, fallas, reversiones, montos netos y recomendaciones verificables. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `accountIndex` | integer | — | Número de la cuenta en la lista que muestra baas_list_accounts (base 1). Precedencia para elegir la cuenta propia: accountValue (sólo si coincide con una cuenta del usuario) → currency (primera cuenta en esa moneda) → accountIndex (base 1: el número que muestra baas_list_accounts) → si hay una sola cuenta, esa. | | `accountValue` | string | — | Sólo si una herramienta ya lo devolvió y coincide con una cuenta del usuario; no escribir números de cuenta de memoria. Precedencia para elegir la cuenta propia: accountValue (sólo si coincide con una cuenta del usuario) → currency (primera cuenta en esa moneda) → accountIndex (base 1: el número que muestra baas_list_accounts) → si hay una sola cuenta, esa. | | `dateFrom` | string | sí | Desde, RFC 3339 | | `dateTo` | string | sí | Hasta, RFC 3339 | | `currency` | string | — | Moneda ISO 4217 | | `direction` | string (OUT | IN) | — | "OUT" enviados, "IN" recibidos; omitido = ambos | | `question` | string | — | Enfoque específico del análisis | | `maxItems` | integer | — | Máximo de pagos (por defecto 300) | | `assignmentId` | string | — | Contexto BaaS (opcional) | **Devuelve** `{ summary }` summary trae account, range, totals {count, succeeded, failed, reversed, pending, successRate}, byCurrency con succeededAmount, reversedAmount, netAmount y averageTicket, failureReasons y sample. El informe redactado viene en el texto. Si no hay pagos en el rango, avisa y no analiza. --- # Validar cuenta destino > Consulta los datos de una cuenta destino antes de enviarle una transferencia: titular, tipo de cuenta, moneda y estado. No mueve dinero. - kind: mcp-tool - status: stable - access: read - last_verified: 2026-10-07 - url: https://tilopay.com/developers/agentes/mcp/api-bancario/validate-destination > Estas herramientas se activan bajo solicitud y sólo funcionan para usuarios con credenciales del API bancario de Tilopay. No forman parte del acceso MCP por defecto: Tilopay habilita el grupo caso por caso. Requiere: Credenciales del API bancario de Tilopay registradas por Tilopay para ese usuario. - `baas_validate_destination` - Acceso: Sólo lectura - Operación del API: `POST /api/public/v1/accounts/validate` — https://tilopay.com/developers/api-bancario/cuentas Valida una cuenta destino antes de transferir: PHONE para SINPE Móvil o IBAN para transferencia a cuenta. Devuelve el nombre del titular que el banco confirma. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `accountType` | string (PHONE | IBAN) | sí | Esquema del identificador: PHONE para SINPE Móvil, IBAN para cuenta. | | `accountValue` | string | sí | Número de teléfono de 8 dígitos locales (sin prefijo de país) o IBAN | | `assignmentId` | string | — | Contexto BaaS (opcional) | **Devuelve** `{ result }` result = datos que devuelve el API bancario sobre la cuenta destino (titular, tipo de cuenta, moneda y estado) antes de enviar una transferencia. No mueve dinero. --- # Enviar transferencia > Crea la intención de una transferencia desde una cuenta bancaria del comercio en el portal Banca Cliente; el pago se ejecuta sólo al confirmarla con el código que llega al correo del comercio. - kind: mcp-tool - status: stable - access: destructive - last_verified: 2026-10-20 - url: https://tilopay.com/developers/agentes/mcp/api-bancario/send-transfer > **Advertencia:** Esta herramienta mueve dinero real. No envía el pago todavía: crea la intención en el portal > Banca Cliente, que valida el destino y envía un código de 6 dígitos al correo del comercio > (vigencia de 30 minutos). El pago se ejecuta sólo al llamar > [baas_confirm_transfer](/developers/agentes/mcp/api-bancario/confirm-transfer) con ese código. > Estas herramientas se activan bajo solicitud y sólo funcionan para usuarios con credenciales del API bancario de Tilopay. No forman parte del acceso MCP por defecto: Tilopay habilita el grupo caso por caso. Requiere: Credenciales del API bancario de Tilopay registradas por Tilopay para ese usuario. - `baas_send_transfer` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones - Operación del API: `POST /api/public/v1/transactions/payments` — https://tilopay.com/developers/api-bancario/pagos Crea la intención de una transferencia desde la cuenta bancaria del comercio en el portal Banca Cliente (todavía no es el pago). El portal valida el destino y envía un código de 6 dígitos al correo del comercio; el pago se ejecuta sólo cuando se llama baas_confirm_transfer con ese código (vigencia de 30 minutos). Método por defecto: SINPE Móvil (destino por teléfono); para transferencia a cuenta, destinationAccountType=IBAN. baas_validate_destination es opcional para mostrar el titular antes; esta herramienta valida el destino por su cuenta. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `amount` | number | sí | Monto a transferir | | `currency` | string | sí | Moneda ISO 4217 (CRC, USD) | | `contactName` | string | — | Nombre del contacto guardado (alternativa a destinationAccountValue; uno de los dos es obligatorio) | | `destinationAccountType` | string (PHONE | IBAN) | — | PHONE = SINPE Móvil (por defecto), IBAN = transferencia a cuenta | | `destinationAccountValue` | string | — | Teléfono: se aceptan +50688887777, 506 8888-7777 u 88887777 y se normaliza a 8 dígitos; IBAN en mayúsculas sin espacios. Alternativa a contactName: uno de los dos es obligatorio. | | `destinationName` | string | — | Nombre del destinatario (si no se valida via contacto) | | `detailReference` | string | — | Concepto de la transferencia (mínimo 15 caracteres) | | `assignmentId` | string | — | No se usa en este flujo | | `allowDuplicate` | boolean | — | Solo true cuando el usuario confirmó literalmente que quiere repetir una transferencia idéntica reciente (por ejemplo 'sí, es otra'). Nunca se activa por iniciativa del agente. | **Devuelve** `{ requires_transfer_code: true, channel: "email", via: "portal", resumen: { beneficiario_nombre, beneficiario_confirmado_por_banco, beneficiario_identificacion_enmascarada, entidad_financiera, destino_tipo, destino_legible, monto, moneda, concepto, origen, datos_no_informados[] }, requires_approval, message }` No devuelve intentId: la intención queda guardada en el servidor. Respuestas especiales: requires_duplicate_confirmation (mismo destino, monto y moneda en 120 s; repetir con allowDuplicate: true sólo si el usuario lo confirmó literalmente) y requires_open_intent_resolution (ya hay una intención abierta: confirmarla con baas_confirm_transfer o cancelarla con baas_cancel_transfer). --- # Confirmar la transferencia > Ejecuta la transferencia cuya intención creó baas_send_transfer, con el código de 6 dígitos que el portal Banca Cliente envió al correo del comercio. - kind: mcp-tool - status: stable - access: destructive - last_verified: 2026-10-20 - url: https://tilopay.com/developers/agentes/mcp/api-bancario/confirm-transfer > **Advertencia:** Esta herramienta mueve dinero real. Ejecuta la transferencia que > [baas_send_transfer](/developers/agentes/mcp/api-bancario/send-transfer) dejó como intención, > usando el código de 6 dígitos que el portal Banca Cliente envió al correo del comercio (vigencia > de 30 minutos). Nunca escribás ni repitás el código en la respuesta. El resultado final no viene en esta respuesta: llega después como aviso del banco (transferencia completada o fallida); no hay que consultarlo. Si la cuenta tiene doble control, la respuesta queda en `awaiting_approval` y el aprobador decide con `banca_decide_approval`. > Estas herramientas se activan bajo solicitud y sólo funcionan para usuarios con credenciales del API bancario de Tilopay. No forman parte del acceso MCP por defecto: Tilopay habilita el grupo caso por caso. Requiere: Credenciales del API bancario de Tilopay registradas por Tilopay para ese usuario. - `baas_confirm_transfer` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones Ejecuta la transferencia cuya intención creó baas_send_transfer, con el código de 6 dígitos que el portal Banca Cliente envió al correo del comercio. Nunca escribas ni repitas el código en la respuesta. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `code` | string | sí | Código de 6 dígitos que el portal Banca Cliente envió al correo del comercio | | `intentId` | string | — | Identificador de la intención (opcional; si se omite, usa la intención abierta del usuario) | **Devuelve** `{ status, via, message }` status = "enviada" o "awaiting_approval"; via = "portal". El resultado final llega después como aviso del banco (transferencia completada o fallida); no hay que consultarlo. --- # Estado de una transferencia > Consulta el estado actual de una transferencia por su payment_id: estado, resultado, monto, moneda, destino y fecha. - kind: mcp-tool - status: stable - access: read - last_verified: 2026-10-20 - url: https://tilopay.com/developers/agentes/mcp/api-bancario/get-transfer-status > Estas herramientas se activan bajo solicitud y sólo funcionan para usuarios con credenciales del API bancario de Tilopay. No forman parte del acceso MCP por defecto: Tilopay habilita el grupo caso por caso. Requiere: Credenciales del API bancario de Tilopay registradas por Tilopay para ese usuario. - `baas_get_transfer_status` - Acceso: Sólo lectura No consulta al banco: indica que el resultado de la transferencia llega como aviso en cuanto el banco lo confirma. paymentId es opcional y no se usa. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `paymentId` | string | — | No se usa (opcional) | **Devuelve** `{ message }` message = texto que explica que el resultado llega como aviso del banco. --- # Otras operaciones > Contextos (assignments), diagnóstico de credenciales, listado de cuentas, saldo de una cuenta, número de cuenta completo, estado de una solicitud de estado de cuenta, cancelación de la transferencia pendiente, aprobación en doble control y cierre de la sesión bancaria, en una sola página. - kind: mcp-tool - status: stable - access: read - last_verified: 2026-10-22 - url: https://tilopay.com/developers/agentes/mcp/api-bancario/otras-operaciones > Estas herramientas se activan bajo solicitud y sólo funcionan para usuarios con credenciales del API bancario de Tilopay. No forman parte del acceso MCP por defecto: Tilopay habilita el grupo caso por caso. Requiere: Credenciales del API bancario de Tilopay registradas por Tilopay para ese usuario. ### Contextos (assignments) del API BaaS [#baas-list-assignments] - `baas_list_assignments` - Acceso: Sólo lectura Lista los contextos tenant/cuenta (assignments) disponibles para las credenciales BaaS del usuario. Úsalo cuando otra herramienta pida assignmentId. **Parámetros** Sin parámetros. **Devuelve** `{ assignments[] }` assignments = contextos disponibles con assignment_id, tenant_code, owner_type, country_code y status. ### Diagnóstico del API BaaS [#baas-diagnostics] - `baas_diagnostics` - Acceso: Sólo lectura Verifica las credenciales BaaS del usuario, el login, el intercambio de token y el acceso a cuentas. Úsalo cuando una consulta BaaS falle. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `assignmentId` | string | — | Contexto a probar (opcional) | **Devuelve** `{ checks[], failed }` checks = una fila por verificación (credenciales, login + assignments, cuentas) con ok y detalle; failed = cuántas fallaron. El correo de la credencial se devuelve enmascarado. ### Listar cuentas BaaS [#baas-list-accounts] - `baas_list_accounts` - Acceso: Sólo lectura - Operación del API: `GET /api/public/v1/accounts` — https://tilopay.com/developers/api-bancario/cuentas Lista las cuentas accesibles del API BaaS (sin saldos): tipo de identificador, valor y moneda. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `accountType` | string | — | Filtro por esquema (IBAN) | | `accountValue` | string | — | Filtro por identificador | | `limit` | integer | — | 1–100, junto con offset | | `offset` | integer | — | Desplazamiento de paginación | | `assignmentId` | string | — | Contexto BaaS (opcional) | **Devuelve** `{ result }` result = respuesta del API bancario tal cual. ### Saldo de una cuenta BaaS [#baas-get-balance] - `baas_get_balance` - Acceso: Sólo lectura - Operación del API: `POST /api/public/v1/accounts/balance` — https://tilopay.com/developers/api-bancario/cuentas Obtiene el saldo actual de una cuenta BaaS. La cuenta se elige por precedencia: accountValue (sólo si coincide con una cuenta del usuario) → currency (primera cuenta en esa moneda) → accountIndex (base 1) → cuenta única. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `currency` | string | — | Moneda de la cuenta (CRC o USD): primera cuenta en esa moneda. Precedencia para elegir la cuenta propia: accountValue (sólo si coincide con una cuenta del usuario) → currency (primera cuenta en esa moneda) → accountIndex (base 1: el número que muestra baas_list_accounts) → si hay una sola cuenta, esa. | | `accountIndex` | integer | — | Número de la cuenta en la lista que muestra baas_list_accounts (base 1). Precedencia para elegir la cuenta propia: accountValue (sólo si coincide con una cuenta del usuario) → currency (primera cuenta en esa moneda) → accountIndex (base 1: el número que muestra baas_list_accounts) → si hay una sola cuenta, esa. | | `accountValue` | string | — | Sólo si una herramienta ya lo devolvió y coincide con una cuenta del usuario; no escribir números de cuenta de memoria. Precedencia para elegir la cuenta propia: accountValue (sólo si coincide con una cuenta del usuario) → currency (primera cuenta en esa moneda) → accountIndex (base 1: el número que muestra baas_list_accounts) → si hay una sola cuenta, esa. | | `assignmentId` | string | — | Contexto BaaS (opcional) | **Devuelve** `{ account: { value, currency }, amounts: { available, posted }, as_of }` account = la cuenta consultada; amounts.available = saldo disponible; amounts.posted = saldo registrado; as_of = fecha de corte. ### Estado de la solicitud de estado de cuenta [#baas-get-statement-status] - `baas_get_statement_status` - Acceso: Sólo lectura - Operación del API: `GET /api/public/v1/accounts/statements/{request_id}` — https://tilopay.com/developers/api-bancario/cuentas Consulta el estado de una solicitud asíncrona de estado de cuenta BaaS. El API responde 200 con status PENDING, PROCESSING, DONE o ERROR. Cuando está DONE incluye download_url, válida por 48 horas, y su vencimiento. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `requestId` | string | sí | request_id devuelto al solicitarlo | | `assignmentId` | string | — | Contexto BaaS (opcional) | **Devuelve** `{ result }` result = respuesta del API bancario tal cual. ### Número de cuenta completo del comercio [#baas-get-account-number] - `baas_get_account_number` - Acceso: Sólo lectura Muestra el IBAN COMPLETO de una cuenta propia del comercio. Úsala SOLO cuando el comercio pide explícitamente su número de cuenta (por ejemplo para dárselo a un cliente o proveedor) y con confirm=true. Queda registrada en la auditoría. En cualquier otra respuesta se usa el número enmascarado. Acepta sólo currency o accountIndex para elegir la cuenta. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `confirm` | boolean | sí | true solo si el comercio pidió explícitamente su número de cuenta completo | | `currency` | string | — | Moneda de la cuenta (CRC o USD) | | `accountIndex` | integer | — | Número de la cuenta en la lista | | `assignmentId` | string | — | Contexto BaaS (opcional) | **Devuelve** `{ result: { account_id, currency, iban } }` result = la cuenta propia con su IBAN completo. ### Cancelar la transferencia pendiente [#baas-cancel-transfer] - `baas_cancel_transfer` - Acceso: Escritura Cancela la transferencia que está esperando el código de autorización. Úsala cuando el comercio diga que no la quiere hacer. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `intentId` | string | — | Identificador de la intención (opcional) | **Devuelve** `{ message }` message = confirmación de la cancelación. ### Aprobar o rechazar una operación pendiente [#banca-decide-approval] - `banca_decide_approval` - Acceso: Sensible - Exige confirmación: https://tilopay.com/developers/agentes/mcp/permisos#confirmaciones El aprobador del doble control aprueba o rechaza una transferencia pendiente, con el código de 6 dígitos que llegó a su correo. Nunca escribas el código en la respuesta. **Parámetros** | Parámetro | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `decision` | string (aprobar | rechazar) | sí | Decisión del aprobador | | `code` | string | sí | Código de 6 dígitos del correo del aprobador | | `approvalId` | string | — | Identificador de la aprobación (opcional; si se omite, se toma la aprobación pendiente más reciente) | | `reason` | string | — | Motivo del rechazo (máx. 255 caracteres, opcional) | **Devuelve** `{ status, message }` status = resultado de la decisión; message = texto de confirmación. ### Cerrar sesión bancaria [#baas-close-session] - `baas_close_session` - Acceso: Escritura Cierra de inmediato la sesión bancaria activa (solo en el Asistente de WhatsApp). **Parámetros** Sin parámetros. **Devuelve** ## Estado y descarga del documento [#estado-documento] `baas_get_statement_status` consulta una solicitud creada de forma asíncrona (`202 ACCEPTED`, `request_id`, `PENDING`). El API responde `200` con `PENDING`, `PROCESSING`, `DONE` o `ERROR`; en `DONE` incluye `download_url`, válida por **48 horas**. --- # Documentación legible por máquina > Los artefactos que el portal publica para agentes: llms.txt, Markdown crudo en cualquier URL, openapi.json y mcp.json. - kind: guide - status: stable - last_verified: 2026-10-20 - url: https://tilopay.com/developers/agentes/documentacion-legible ## Índices para modelos [#llms] - [tilopay.com/llms.txt](https://tilopay.com/llms.txt) — índice del sitio en español, con la URL y una descripción de cada página. - [tilopay.com/llms-full.txt](https://tilopay.com/llms-full.txt) — el mismo índice con el contenido completo. - [tilopay.com/en/llms.txt](https://tilopay.com/en/llms.txt) y [tilopay.com/en/llms-full.txt](https://tilopay.com/en/llms-full.txt) — las versiones en inglés, con las URLs `/en`. ## Markdown crudo [#markdown] Cualquier URL del sitio devuelve su Markdown agregándole `.md`: por ejemplo [tilopay.com/developers/sdk/instalacion.md](https://tilopay.com/developers/sdk/instalacion.md) o [tilopay.com/tarifas.md](https://tilopay.com/tarifas.md). Se sirve como `text/markdown`, con un encabezado de metadatos (tipo de página, estado, versión y fecha de última verificación). Una URL que no existe devuelve 404, no HTML. ## Spec del API [#openapi] [Cobros con tarjetas guardadas](/developers/api/cobros-tarjetas-guardadas) incluye las 10 operaciones públicas collect en el OpenAPI de adquirencia. - [`openapi.json`](/developers/openapi.json) — spec OpenAPI 3.1 del API de Tilopay: endpoints, parámetros, respuestas y ejemplos. Es la fuente de verdad del API. - [`openapi.yaml`](/developers/openapi.yaml) — el mismo contenido en YAML. - [`api-bancario/openapi.json`](/developers/api-bancario/openapi.json) — spec OpenAPI 3.0.3 del API Bancario (BaaS), un artefacto separado del API de adquirencia. - [`api-bancario/openapi.yaml`](/developers/api-bancario/openapi.yaml) — el mismo contenido en YAML. Las dos rutas responden con `Access-Control-Allow-Origin: *`, así que se pueden leer desde el navegador. ## Catálogo del MCP [#mcp-json] [`mcp.json`](/developers/mcp.json) describe el servidor MCP: su URL, el modelo de acceso y el catálogo completo de herramientas con parámetros, salida y nivel de acceso. Cuando la herramienta envuelve una operación del API, la entrada incluye ese endpoint. El catálogo está en español: las descripciones de las herramientas se escriben para el asistente de WhatsApp y se publican tal cual. El índice de las skills instalables está en [`/developers/skills/index.md`](/developers/skills/index.md). El campo `verified_at` en la raíz trae la fecha (`YYYY-MM-DD`) en que el catálogo se comparó con el servidor. La versión del servidor no cambia cuando se agregan herramientas, así que ésa es la señal que conviene mirar para saber si una copia en caché quedó vieja. ---