products-payment-refacil-mcp
v1.2.7
Published
MCP Server para la API products-payment-refacil
Downloads
327
Readme
products-payment-refacil MCP Server
Servidor MCP (Model Context Protocol) generado automáticamente para la API products-payment-refacil.
🚀 Características
- 21 herramientas generadas automáticamente desde la colección Postman
- Autenticación flexible: secretId con renovación automática de tokens
- Servidor HTTP con Fastify
- Protocolo MCP estándar para integración con IDEs
📋 Requisitos
- Node.js 20+
- npm o yarn
📦 Instalación desde NPM
Si este paquete está publicado en npm, puedes instalarlo globalmente:
# Instalación global (recomendado)
npm install -g products-payment-refacil-mcp
# Verificar instalación
products-payment-refacil-mcp --versionConfiguración Rápida en IDEs
Cursor
- Abrir Settings → Features → Model Context Protocol
- Click en "Edit Config"
- Agregar:
Windows: %APPDATA%\Cursor\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json
macOS/Linux: ~/.config/Cursor/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json
{
"mcpServers": {
"products-payment-refacil": {
"command": "products-payment-refacil-mcp",
"env": {
"BASE_URL": "https://products-payment-api.qa.refacil.co",
"SECRET_ID": "tu-secret-id",
"AUTH_ENDPOINT": "/auth/generate-token",
"TOKEN_CACHE_TTL": "3600"
}
}
}
}- Reiniciar Cursor
Claude Desktop
Editar archivo de configuración:
Windows: %APPDATA%\Claude\claude_desktop_config.json
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Linux: ~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"products-payment-refacil": {
"command": "products-payment-refacil-mcp",
"env": {
"BASE_URL": "https://products-payment-api.qa.refacil.co",
"SECRET_ID": "tu-secret-id",
"AUTH_ENDPOINT": "/auth/generate-token",
"TOKEN_CACHE_TTL": "3600"
}
}
}
}Reiniciar Claude Desktop.
Visual Studio Code
- Instalar extensión MCP for VS Code
- Editar
settings.json:
{
"mcp.servers": {
"products-payment-refacil": {
"command": "products-payment-refacil-mcp",
"env": {
"BASE_URL": "https://products-payment-api.qa.refacil.co",
"SECRET_ID": "tu-secret-id",
"AUTH_ENDPOINT": "/auth/generate-token",
"TOKEN_CACHE_TTL": "3600"
}
}
}
}- Recargar VS Code
🛠️ Instalación para Desarrollo
Si quieres contribuir o ejecutar desde el código fuente:
# Clonar el repositorio
git clone https://github.com/refacil/products-payment-refacil-mcp.git
cd products-payment-refacil-mcp
# Instalar dependencias
npm install
# Construir el proyecto
npm run build
# Iniciar en desarrollo
npm run dev
# Iniciar en producción
npm start🔧 Configuración
El servidor se configura mediante variables de entorno:
# Copiar archivo de ejemplo
cp .env.example .env
# Editar configuración
nano .envVariables de Entorno
| Variable | Descripción | Valor por defecto |
|----------|-------------|-------------------|
| PORT | Puerto del servidor | 3008 |
| ENVIRONMENT | Entorno de ejecución | development |
| BASE_URL | URL base de la API | https://products-payment-api.qa.refacil.co |
| SECRET_ID | ID secreto para autenticación | 0d92fc6aa394c13... (your secret id) |
| AUTH_ENDPOINT | Endpoint de autenticación | /auth/generate-token |
| TOKEN_CACHE_TTL | TTL del caché de tokens (segundos) | 3600 |
| MCP_TOKEN | Token de autenticación del MCP | mcp-secret-token-123 |
🐳 Docker
# Construir imagen
docker build -t products-payment-refacil-mcp .
# Ejecutar contenedor
docker run -p 3008:3008 products-payment-refacil-mcp
# O usar docker-compose
docker-compose up☸️ Kubernetes
# Aplicar manifests
kubectl apply -f k8s/
# Verificar despliegue
kubectl get pods -l app=products-payment-refacil-mcp🔌 Uso del MCP
Endpoints Disponibles
/mcp: Endpoint principal del protocolo MCP/health: Health check del servidor/tools: Lista de herramientas disponibles
Modo Multi-Usuario (HTTP)
El servidor MCP soporta múltiples usuarios simultáneamente en modo HTTP mediante el header X-Secret-ID.
¿Cómo funciona?
- Sin
X-Secret-ID: Usa elSECRET_IDdel archivo.env(modo single-user) - Con
X-Secret-ID: Usa el secretId proporcionado en el header (modo multi-user)
Ejemplo de uso:
# Usuario 1
curl -X POST http://localhost:3008/mcp \
-H "Authorization: Bearer mcp-token" \
-H "X-Secret-ID: user1-secret-id" \
-H "Content-Type: application/json" \
-d '{"method": "tools/call", "params": {...}}'
# Usuario 2
curl -X POST http://localhost:3008/mcp \
-H "Authorization: Bearer mcp-token" \
-H "X-Secret-ID: user2-secret-id" \
-H "Content-Type: application/json" \
-d '{"method": "tools/call", "params": {...}}'Ventajas del Modo Multi-Usuario:
- ✅ Cada usuario usa sus propias credenciales
- ✅ Tokens cacheados por secretId (mejor performance)
- ✅ Un solo servidor para múltiples clientes
- ✅ Compatible con modo single-user (fallback al .env)
🛠️ Herramientas Disponibles
auth_generate_token
Endpoints para autenticación y generación de tokens
Genera un token JWT usando el secretId del cliente. Este token debe ser usado en todas las peticiones posteriores junto con el secretId.
🔑 MANEJO GLOBAL DE ERRORES 401 - AUTENTICACIÓN:
⚠️ IMPORTANTE: Este endpoint es la base para resolver errores de autenticación en TODOS los endpoints protegidos.
🔄 Flujo de Resolución de Errores 401:
1. Cuando recibas un error 401 en cualquier endpoint:
{
"statusCode": 401,
"message": "Error de autenticación",
"date": 1754924521985,
"payload": {
"error": "AUTHENTICATION_ERROR",
"details": "Authentication failed",
"originalStatus": 401
}
}
2. Acciones inmediatas a realizar:
✅ Verificar que tus datos de autenticación sean correctos
✅ Regenerar un nuevo token usando este endpoint (
/auth/generate-token)✅ Reintentar la operación original con el nuevo token
💡 Mejor práctica: Implementa retry automático para errores 401 antes de fallar.
📋 Flujo de resolución detallado:
Token expirado: Llamar este endpoint con tu
secretIdToken inválido: Verificar formato y regenerar si es necesario
Secret ID incorrecto: Usar el mismo
secretIddel token originalHeaders faltantes: Incluir
Authorization: Bearer {token}yx-secret-id: {secretId}
🔄 Ejemplo de retry automático:
// Si recibes 401, regenera token y reintenta
if (error.statusCode === 401) {
const newToken = await generateNewToken(secretId);
// Reintentar operación original con nuevo token
}
🎯 Aplicable a todos los endpoints protegidos:
📦 Productos y categorías
🛒 Solicitudes de producto
💳 Creación de pagos
🔄 Reembolsos
Y cualquier otro endpoint que requiera autenticación
Respuesta exitosa (200):
{
"statusCode": 200,
"message": "Token generado exitosamente",
"date": 1704441600000,
"payload": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 360
}
}
Campos del payload:
token(string): Token JWT para autenticaciónexpiresIn(number): Tiempo de expiración en minutos (ej: 360 = 6 horas)
🤖 Automatización en Postman:
Este endpoint incluye un script automático que:
✅ Guarda el token en la variable
{{token}}de la colección✅ Valida que la respuesta sea exitosa
✅ Muestra logs informativos en la consola
✅ Maneja errores automáticamente
Resultado: Los siguientes endpoints usarán automáticamente el token generado.
Respuesta de error (400):
{
"statusCode": 400,
"message": "Datos de entrada inválidos",
"date": 1704441600000,
"payload": {
"error": "VALIDATION_ERROR"
}
}
Parámetros:
| Name | Type | Description | | --- | --- | --- | | secretId | string | Campo del body: secretId |
health_check_health_check_get
Verificación del estado de la API y conectividad con servicios
Verifica el estado de la API y servicios internos.
Respuesta exitosa (200):
{
"statusCode": 200,
"message": "API funcionando correctamente",
"date": 1704441600000,
"payload": {
"status": "ok",
"timestamp": "2024-01-15T10:30:45.123Z",
"uptime": 3600,
"version": "1.0.0",
"environment": "development"
}
}Respuesta con error (503):
{
"statusCode": 503,
"message": "API con problemas de conectividad",
"date": 1704441600000,
"payload": {
"status": "error",
"timestamp": "2024-01-15T10:30:45.123Z",
"uptime": 3600,
"error": "Connection timeout",
"version": "1.0.0",
"environment": "development"
}
}status
Verificación del estado de la API y conectividad con servicios
Verifica conectividad de la API contra el core service.
products_categories
Endpoints para consultar categorías y productos disponibles
Retorna las categorías de productos que el cliente puede acceder.
Headers requeridos:
Authorization: Bearer {token}x-secret-id: {secretId}
Respuesta exitosa (200):
{
"statusCode": 200,
"message": "Categorías obtenidas exitosamente",
"date": 1704441600000,
"payload": [
{
"id": 1,
"name": "Recargas",
"description": "Recargas de celular",
"enabled": true
},
{
"id": 2,
"name": "Pines",
"description": "Pines de servicios",
"enabled": true
}
]
}Respuesta de error (401):
{
"statusCode": 401,
"message": "Error de autenticación",
"date": 1754924521985,
"payload": {
"error": "AUTHENTICATION_ERROR",
"details": "Authentication failed",
"originalStatus": 401
}
}products_by_cus_and_category
Endpoints para consultar categorías y productos disponibles
Retorna los productos filtrados por cliente y categoría.
Headers requeridos:
Authorization: Bearer {token}x-secret-id: {secretId}
Body (JSON):
categoryId(number, requerido): ID de la categoríalimit(number, opcional): Número máximo de productos (default: 10)offset(number, opcional): Número de productos a omitir (default: 0)searchText(string, opcional): Texto para buscar en productos
Ejemplo de Request:
{
"categoryId": 120,
"limit": 10,
"offset": 0,
"searchText": "BANCAMIA"
}
Respuesta exitosa (200):
{
"statusCode": 200,
"message": "Productos obtenidos exitosamente",
"date": 1754924866513,
"payload": {
"products": [
{
"id": 1,
"name": "BANCAMIA",
"amount": null,
"meta": {
"partial": "false",
"overdue": "true",
"type": "RECAUDO CODIGO BARRAS",
"fnArgs": "1,25,44"
},
"description": null,
"image_url": "bills/52368.png",
"query_type": "BILLData",
"sell_type": "Bill",
"agreement": "7700000000001",
"template_data_request": {
"cellphone": "3208888888",
"reference": "123456789"
}
},
{
"id": 16045,
"name": "LIBERACION DE CUPO BANCAMIA",
"amount": null,
"meta": {
"fnArgs": 43278,
"categoryId": 43,
"form": [
{
"active": true,
"type": "text",
"label": "Numero De Documento",
"placeholder": "Ingrese su NUMERO DE DOCUMENTO",
"legend": "NUMERO DE DOCUMENTO",
"value": "reference",
"required": true
},
{
"active": true,
"type": "text",
"label": "Codigo De Corresponsal",
"placeholder": "Ingrese su CODIGO DE CORRESPONSAL",
"legend": "CODIGO DE CORRESPONSAL",
"value": "reference2",
"required": true
}
]
},
"description": null,
"image_url": "bill.png",
"query_type": "BILLData",
"sell_type": "Bill",
"agreement": "2010910",
"template_data_request": {
"cellphone": "3208888888",
"reference": "123456789",
"reference2": "123548"
}
}
]
}
}
📋 Datos para Solicitud de Producto:
Esta respuesta contiene información clave que se debe usar para crear una solicitud de producto:
id: ID del producto (se usa enproduct-requests/create)query_type: Tipo de consulta (se usa enproduct-requests/create)sell_type: Tipo de venta (se usa enproduct-requests/create)agreement: Acuerdo del producto (se puede usar enproduct-requests/create)template_data_request: Template para el campodataenproduct-requests/createamount: Monto del producto (puede sernullpara productos con consulta previa)
Notas importantes:
template_data_request: Es un template que muestra la estructura de datos que se debe enviar en el campodatacuando se crea una solicitud de producto para esta categoría específica. Los valores son ejemplos y deben ser reemplazados con datos reales.datadinámico: El campodataen las solicitudes de producto es dinámico y su estructura depende de la categoría. Cada categoría puede requerir diferentes campos y formatos.Objeto
meta: Es dinámico y puede contener información diferente para cada producto. No se define una estructura fija debido a su naturaleza variable.Tipos de producto: Los productos pueden tener diferentes tipos de
query_typeysell_typesegún la categoría.Campo
amount: Puede sernullpara productos que requieren consulta previa (como facturas), o contener un valor específico para productos de pago directo.
🔄 Flujo de Uso:
Consultar productos con este endpoint
Seleccionar producto de la lista
Usar datos del producto para crear solicitud en
product-requests/createUsar template_data_request como referencia para el campo
dataDeterminar amount según el tipo de producto (null para consulta previa, valor para pago directo)
Respuesta de error (401):
{
"statusCode": 401,
"message": "Error de autenticación",
"date": 1754924521985,
"payload": {
"error": "AUTHENTICATION_ERROR",
"details": "Authentication failed",
"originalStatus": 401
}
}
Parámetros:
| Name | Type | Description | | --- | --- | --- | | categoryId * | number | ID de la categoría | | limit | number | Número máximo de productos (default: 10) | | offset | number | Número de productos a omitir (default: 0) | | searchText | string | Texto para buscar en productos |
product_requests_quote
Endpoints para crear solicitudes de productos
Cotiza el valor de un producto que requiere consulta previa sin crear una solicitud de compra ni agregarlo al carrito. Este endpoint es ideal para mostrar el monto al usuario antes de que decida comprar.
🎯 Casos de Uso:
- Consulta de Facturas: Mostrar el valor adeudado antes de agregar al carrito
- SOAT: Verificar precio del seguro antes de comprar
- Servicios Públicos: Ver monto a pagar antes de proceder
- Cualquier producto con consulta previa: Obtener precio sin compromiso de compra
✅ Ventajas:
- No crea carrito ni solicitud de compra
- Solo consulta y guarda trazabilidad
- Usuario puede ver el monto antes de decidir
- Analytics de cotizaciones vs compras
📊 Vinculación Automática:
Si el usuario decide comprar usando /product-requests/create con los mismos datos, el sistema:
- Vincula automáticamente la cotización con la compra
- Permite análisis de tasa de conversión
- Identifica usuarios que cotizaron pero no compraron
Headers requeridos:
Authorization: Bearer {token}x-secret-id: {secretId}
Body (JSON):
category_id(number, requerido): ID de la categoríaid(number, requerido): ID del productoamount(number|null, opcional): Usarnullpara productos con consulta previadata(object, requerido): Datos específicos del productoquery_type(string, requerido): Tipo de consulta (BILLData, PLATE_QUERY, etc.)sell_type(string, requerido): Tipo de venta (debe requerir consulta previa)agreement(string, opcional): Acuerdo del producto
⚠️ Importante:
- Solo funciona para productos que requieren consulta previa
- Para productos directos, usar
/product-requests/create - No retorna medios de pago (solo el monto cotizado)
Respuesta exitosa (200):
{
"statusCode": 200,
"message": "Cotización realizada exitosamente",
"date": 1733932800000,
"payload": {
"quoteId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"amount": 150000,
"status": "SUCCESS",
"data": {
"reference": "123456789",
"customerName": "JUAN PEREZ",
"address": "Calle 123"
}
}
}Campos de la respuesta:
quoteId: ID de la cotización guardadaamount: Monto cotizadostatus: Estado de la cotización (SUCCESS, INVALID, FAILED)data: Datos adicionales del producto consultado
Respuesta de error (400) - Producto directo:
{
"statusCode": 400,
"message": "Este producto no requiere cotización previa",
"date": 1733932800000,
"payload": {
"error": "PRODUCT_DOES_NOT_REQUIRE_QUOTE",
"message": "Use el endpoint /create para compra directa"
}
}Respuesta de error (400) - Datos inválidos:
{
"statusCode": 400,
"message": "Datos inválidos para la cotización",
"date": 1733932800000,
"payload": {
"quoteId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "INVALID",
"error": "Referencia no encontrada"
}
}🔄 Flujo Completo:
1. Cotizar producto:
POST /product-requests/quote
{
"category_id": 120,
"id": 52368,
"data": {"reference": "123456789"},
"query_type": "BILLData",
"sell_type": "Bill"
}Respuesta: {"quoteId": "...", "amount": 150000}
2. Usuario decide comprar (mismo request):
POST /product-requests/create
{
"category_id": 120,
"id": 52368,
"data": {"reference": "123456789"},
"query_type": "BILLData",
"sell_type": "Bill"
}Resultado: Sistema vincula automáticamente la cotización con la compra para analytics.
Parámetros:
| Name | Type | Description |
| --- | --- | --- |
| category_id * | number | ID de la categoría |
| id * | number | ID del producto |
| amount | null | Usar null para productos con consulta previa |
| data * | object | Datos específicos del producto |
| query_type * | null | Tipo de consulta (BILLData, PLATE_QUERY, etc.) |
| sell_type * | string | Tipo de venta (debe requerir consulta previa) |
| agreement | string | Acuerdo del producto |
product_requests_create
Endpoints para crear solicitudes de productos
Crea una nueva solicitud de producto. Esta es la primera etapa del proceso de pago.
📋 Relación con Endpoint de Productos:
Los datos para crear esta solicitud provienen principalmente del endpoint products/by-customer-and-category:
category_id: ID de la categoría (del endpoint de productos)id: ID del producto seleccionado (del campoiddel producto)query_type: Tipo de consulta (del campoquery_typedel producto)sell_type: Tipo de venta (del camposell_typedel producto)data: Estructura basada entemplate_data_requestdel productoagreement: Acuerdo del producto (del campoagreementdel producto)
Headers requeridos:
Authorization: Bearer {token}x-secret-id: {secretId}
Body (JSON):
category_id(number, requerido): ID de la categoría (obtenido del endpoint de productos)id(number, requerido): ID del producto seleccionado (obtenido del campoiddel producto)amount(number|null, opcional): Monto del producto (ver reglas de uso)data(object, requerido): Datos específicos del producto basados entemplate_data_requestdel productoquery_type(string, requerido): Tipo de consulta del producto (PHONE_QUERY, PLATE_QUERY, etc.)sell_type(string, requerido): Tipo de venta del producto (DIRECT_SALE, QUERY_FIRST)agreement(string, opcional): Aceptación de términos (puede venir del campoagreementdel producto)customer_id(string, opcional): Identificador único del usuario o dispositivosubcustomer_id(string, opcional): Identificador del subcliente o cuenta hija asociada alcustomer_idcart_id (string, opcional): identificador del carrito de compra al que se quiere agregar la solicictud de producto
📋 Reglas para el campo customer_id:
🔑 Con Usuario Registrado:
Enviar: ID único del usuario en tu sistema
Ejemplo: "customer_id": "user_12345" o "customer_id": "cliente_abc123"
Uso: Para seguimiento, historial de transacciones, y análisis de comportamiento
📱 Sin Usuario Registrado (Frontend Anónimo):
Enviar: Identificador único del dispositivo o sesión
Ejemplos:
Device ID: "customer_id": "device_abc123def456"
Session ID: "customer_id": "session_xyz789"
Browser Fingerprint: "customer_id": "browser_fp_123"
Local Storage ID: "customer_id": "local_456"
Uso: Para seguimiento de transacciones anónimas y análisis de patrones
💡 Mejores Prácticas:
Consistencia: Usar el mismo formato de ID en toda la aplicación
Persistencia: Mantener el ID durante toda la sesión del usuario
Privacidad: No incluir información personal identificable en el ID
Longitud: Recomendado entre 10-50 caracteres
🔄 Flujo de Implementación:
1. Usuario Registrado:
const customerId = user.id || user.customerId || user.uuid;
// customerId = "user_12345"
2. Usuario Anónimo:
// Generar ID único del dispositivo
const deviceId = generateDeviceId(); // "device_abc123def456"
const sessionId = generateSessionId(); // "session_xyz789"
const customerId = deviceId || sessionId;
3. Envío en Request:
{
"category_id": 120,
"id": 1952,
"amount": null,
"data": {
"cellphone": "3208385715",
"reference": "123456"
},
"query_type": "BILLData",
"sell_type": "Bill",
"agreement": "2010910",
"customer_id": "device_abc123def456",
"subcustomer_id": "subcust_01"
}
📊 Beneficios del Tracking:
Análisis: Comportamiento de usuarios anónimos vs registrados
Seguimiento: Transacciones por dispositivo/sesión
Fraude: Detección de patrones sospechosos
UX: Mejora de la experiencia del usuario
💰 Reglas para el campo amount****:
amount: null: Para productos que generan consulta previa (ej: facturas, servicios con tarifas variables)amount: valor: Para productos de pago directo con precio fijo (ej: recargas, productos con precio conocido)Validación interna: El sistema valida internamente y solo toma el amount del cliente cuando aplica
🔄 Flujo de Creación de Solicitud:
1. Consultar productos:
GET /products/by-customer-and-category
{
"categoryId": 120,
"limit": 10,
"offset": 0,
"searchText": "ACACIAS"
}
2. Respuesta del endpoint de productos:
{
"statusCode": 200,
"message": "Productos obtenidos exitosamente",
"date": 1754945365966,
"payload": {
"template_data_request": {
"cellphone": "3208888888",
"reference": "123456789"
},
"products": [
{
"id": 1952,
"name": "ACACIAS DEL CASTILLO CONJUNTO 3 CALI",
"amount": null,
"meta": {
"fnArgs": 20363,
"categoryId": 44,
"form": [
{
"active": true,
"type": "text",
"label": "Numero De Casa",
"placeholder": "Ingrese su Numero de Casa",
"legend": "Numero de Casa",
"value": "reference",
"required": true
}
]
},
"description": null,
"image_url": "bill.png",
"query_type": "BILLData",
"sell_type": "Bill",
"agreement": "2010910"
}
]
}
}
3. Crear solicitud usando datos del producto:
{
"category_id": 120,
"id": 1952,
"amount": null,
"data": {
"cellphone": "3208385715",
"reference": "123456"
},
"query_type": "BILLData",
"sell_type": "Bill",
"agreement": "2010910"
}
Respuesta exitosa (201):
{
"statusCode": 201,
"message": "Solicitud creada exitosamente",
"date": 1754945173974,
"payload": {
"cartId": "25894df4-a599-4d28-a2f2-bb5b8faa678b",
"requestId": "15974df4-a599-4d28-a2f2-bb5b8faa678b",
"amount": 9999,
"paymentMethods": [
{
"id": 304135,
"name": "Transfiya",
"internal_name": "AppFormTransfiya",
"description": "Transfiya",
"categoryid": 176,
"image": "transfiya.png",
"template_data_request": {
"cellphone": "3208888888"
},
"cost": 500
},
{
"id": 56,
"name": "PSE",
"internal_name": "AppFormPse",
"description": "PSE",
"categoryid": 61,
"image": "pse.png",
"template_data_request": {
"name": "Juan Perez",
"email": "[email protected]",
"bankId": "1007",
"cellphone": "3208888888",
"typePerson": "0",
"documentType": "CC",
"documentNumber": "1032222222"
},
"cost": 500
},
{
"id": 88,
"name": "Nequi",
"internal_name": "AppFormNequiCargar",
"description": "Botón de pago nequi",
"categoryid": 176,
"image": "nequi-responsive.png",
"template_data_request": {
"cellphone": "3208888888"
},
"cost": 500
},
{
"id": 53,
"name": "Bancolombia",
"internal_name": "AppFormDefault",
"description": "Botón de pago Bancolombia",
"categoryid": 177,
"image": "bancolombia.png",
"template_data_request": {
"name": "Juan Perez",
"email": "[email protected]",
"bankId": "1007",
"cellphone": "3208888888",
"typePerson": "0",
"documentType": "CC",
"documentNumber": "1032222222"
},
"cost": 500
},
{
"id": 89,
"name": "Daviplata",
"internal_name": "AppFormDaviplataPse",
"description": "Botón de pago daviplata",
"categoryid": 176,
"image": "daviplata.png",
"template_data_request": {
"cellphone": "3208888888"
},
"cost": 500
}
]
}
}
📋 Datos de la Respuesta:
**
cartId:**Identificador unico del carrito al que se asigno la solicitud de producto (se usa en/products-payment/create)requestId: Identificador único de la solicitud de productoamount: Monto que se debe pagar (calculado por el sistema)additionalData: Datos adicionales del producto (solo si aplica)paymentMethods: Array con medios de pago disponibles
💳 Información de Medios de Pago:
Cada medio de pago contiene:
id: ID del medio de pago (se usa en/products-payment/create)name: Nombre del medio de pagocategoryid: ID de la categoría del medio de pago (se usa en/products-payment/create)template_data_request: Template para el campodataen/products-payment/createcost: Costo del medio de pago para esta transacción (0 = sin costo, >0 = con costo)
🔄 Siguiente Paso - Crear Pago:
Con la respuesta de este endpoint, puedes proceder a crear el pago usando /products-payment/create enviando:
cartId: Del campocartIdde la respuestaid: Del campoiddel medio de pago seleccionadocategoryid: Del campocategoryiddel medio de pago seleccionadodata: Basado entemplate_data_requestdel medio de pago seleccionado
Respuesta de error (403):
{
"statusCode": 403,
"message": "Acceso denegado - Categoría no permitida",
"date": 1704441600000,
"payload": {
"error": "CATEGORY_NOT_ALLOWED"
}
}
Respuesta de error (401):
{
"statusCode": 401,
"message": "Error de autenticación",
"date": 1754924521985,
"payload": {
"error": "AUTHENTICATION_ERROR",
"details": "Authentication failed",
"originalStatus": 401
}
}
Parámetros:
| Name | Type | Description |
| --- | --- | --- |
| category_id * | number | ID de la categoría (obtenido del endpoint de productos) |
| id * | number | ID del producto seleccionado (obtenido del campo id del producto) |
| amount | null | Monto del producto (ver reglas de uso) |
| data * | object | Datos específicos del producto basados en template_data_request del producto |
| query_type * | string | Tipo de consulta del producto (PHONE_QUERY, PLATE_QUERY, etc.) |
| sell_type * | string | Tipo de venta del producto (DIRECT_SALE, QUERY_FIRST) |
| agreement | string | Aceptación de términos (puede venir del campo agreement del producto) |
| customer_id | string | Identificador único del usuario o dispositivo |
| subcustomer_id | string | Identificador del subcliente o cuenta hija asociada al customer_id |
| cart_id | string | identificador del carrito de compra al que se quiere agregar la solicictud de producto |
product_requests_status
Endpoints para crear solicitudes de productos
Consulta el estado actual de una solicitud de producto individual por su requestId o de un carrito completo por su cartId.
🔒 Seguridad:
Este endpoint incluye validación de seguridad que garantiza que solo puedas consultar el estado de las solicitudes/carritos que creaste.
📋 Parámetros:
Debes proporcionar al menos uno de los siguientes parámetros:
requestId(string, opcional): ID único de la solicitud de producto individual (UUID)cartId(string, opcional): ID único del carrito de compras (UUID)
Headers requeridos:
Authorization: Bearer {token}x-secret-id: {secretId}
📊 Estados Posibles:
🔄 Estados de Proceso:
INITIATED: Solicitud creada y en proceso de validaciónQUERIED: Solicitud consultada exitosamente en API externaPENDING: Solicitud lista para procesar el pagoWAITING_PAYMENT: Esperando confirmación de pago del proveedor
❌ Estados de Error:
INVALID: Datos inválidos en la validación del productoDISCARDED: Usuario decidió no continuar con el pago del productoEXPIRED: La solicitud de producto ha expirado
✅ Estados Finales:
SOLD: Pago exitoso y producto vendidoREFUNDED: Pago exitoso pero venta fallóCANCELLED: Usuario no realizó el pago del producto, el proveedor no confirmó el pago
🔄 Flujo de Uso - Producto Individual:
1. Consultar estado usando requestId:
POST /product-requests/status
{
"requestId": "15974df4-a599-4d28-a2f2-bb5b8faa678b"
}
2. Respuesta del estado (producto individual):
{
"statusCode": 200,
"message": "Estado consultado exitosamente",
"date": 1770307880382,
"payload": {
"id": "019a3c15-9d0c-734b-8346-617d6ba466d8",
"cartId": "019a3c15-9cfc-7c3a-82ff-d87477378092",
"status": "SOLD",
"description": "Pago exitoso y producto vendido",
"details": {
"id": 1952,
"categoryId": 120,
"data": {
"cellphone": "3208385716",
"reference": "12345678"
},
"amount": 9999,
"sellType": "Bill",
"queryType": "BILLData",
"agreement": "2010910",
"customer_id": "customer_124"
},
"urlInvoice": "https://prep.refacil.co/#/factura/215765/10549",
"urlSummary": "https://mf-core.refacil.co/refacilpay/resumen/62/28137590-b69d-11f0-8c08-b71754a3ac6b"
}
}
🛒 Flujo de Uso - Carrito Completo:
1. Consultar estado usando cartId:
POST /product-requests/status
{
"cartId": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
2. Respuesta del estado (carrito completo):
{
"statusCode": 200,
"message": "Estado consultado exitosamente",
"date": 1770307754145,
"payload": {
"cartId": "019a3c15-9cfc-7c3a-82ff-d87477378092",
"status": "COMPLETED",
"totalAmount": "9999.00",
"itemsCount": 1,
"urlSummary": "https://mf-core.refacil.co/refacilpay/resumen/62/28137590-b69d-11f0-8c08-b71754a3ac6b",
"products": [
{
"id": "019a3c15-9d0c-734b-8346-617d6ba466d8",
"cartId": "019a3c15-9cfc-7c3a-82ff-d87477378092",
"status": "SOLD",
"description": "Pago exitoso y producto vendido",
"details": {
"id": 1952,
"categoryId": 120,
"data": {
"cellphone": "3208385716",
"reference": "12345678"
},
"amount": "9999.00",
"sellType": "Bill",
"queryType": "BILLData",
"agreement": "2010910",
"customer_id": "customer_124"
},
"urlInvoice": "https://prep.refacil.co/#/factura/215765/10549"
}
]
}
}
🔐 Validación de Seguridad:
Usuario autenticado: Solo puedes consultar solicitudes/carritos creados con tu
secretIdID válido: Debe ser un UUID válido
Acceso restringido: No puedes consultar solicitudes/carritos de otros usuarios
📱 Casos de Uso:
Frontend: Mostrar estado actual al usuario
Backend: Seguimiento de transacciones
Webhooks: Complementar notificaciones asíncronas
Auditoría: Verificar estado de solicitudes
Carrito: Consultar estado de múltiples productos a la vez
Respuesta de error (400 - Parámetros faltantes):
{
"statusCode": 400,
"message": "Debe proporcionar requestId o cartId",
"date": 1754945173974,
"payload": {
"error": "MISSING_REQUIRED_PARAMETER"
}
}
Respuesta de error (404):
{
"statusCode": 404,
"message": "Solicitud de producto no encontrada",
"date": 1754945173974,
"payload": {
"error": "PRODUCT_REQUEST_NOT_FOUND"
}
}
💡 Tip para Testing:
Usa la variable {{lastCartId}} o {{lastRequestId}} que se llenan automáticamente al crear solicitudes.
Parámetros:
| Name | Type | Description | | --- | --- | --- | | requestId | string | Campo del body: requestId | | cartId | string | Campo del body: cartId |
product_requests_discard
Endpoints para crear solicitudes de productos
Descarta una solicitud de producto individual por su requestId o un carrito completo con todos sus productos por su cartId.
🔒 Seguridad:
Este endpoint incluye validación de seguridad que garantiza que solo puedas descartar solicitudes/carritos que creaste.
📋 Parámetros:
Debes proporcionar al menos uno de los siguientes parámetros:
requestId(string, opcional): ID único de la solicitud de producto individual (UUID)cartId(string, opcional): ID único del carrito de compras (UUID)
Headers requeridos:
Authorization: Bearer {token}x-secret-id: {secretId}
⚠️ Condiciones para Descartar:
Para producto individual:
El producto debe estar en estado
PENDINGDebe pertenecer al usuario autenticado
Para carrito completo:
El carrito debe estar en estado
ACTIVEDebe pertenecer al usuario autenticado
Debe tener al menos un producto en estado
PENDING
🔄 Flujo de Uso - Producto Individual:
1. Descartar producto usando requestId:
POST /product-requests/discard
{
"requestId": "15974df4-a599-4d28-a2f2-bb5b8faa678b"
}
2. Respuesta (producto individual):
{
"statusCode": 200,
"message": "Solicitud descartada exitosamente",
"date": 1754945173974,
"payload": {
"requestId": "15974df4-a599-4d28-a2f2-bb5b8faa678b",
"status": "DISCARDED"
}
}
🛒 Flujo de Uso - Carrito Completo:
1. Descartar carrito usando cartId:
POST /product-requests/discard
{
"cartId": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
2. Respuesta (carrito completo):
{
"statusCode": 200,
"message": "Carrito descartado exitosamente (2 productos)",
"date": 1754945173974,
"payload": {
"cartId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "CANCELLED",
"discardedCount": 2,
"products": [
{
"requestId": "20db2a40-77b7-11f0-85d4-7d462019c921",
"status": "DISCARDED"
},
{
"requestId": "30db2a40-77b7-11f0-85d4-7d462019c922",
"status": "DISCARDED"
}
]
}
}
🔐 Validación de Seguridad:
Usuario autenticado: Solo puedes descartar solicitudes/carritos creados con tu
secretIdID válido: Debe ser un UUID válido
Acceso restringido: No puedes descartar solicitudes/carritos de otros usuarios
📱 Casos de Uso:
Usuario cambia de opinión: Descarta producto antes de pagar
Datos incorrectos: Usuario ingresó datos equivocados
Monto muy alto: Usuario no esperaba ese monto
Limpiar carrito: Descartar todos los productos de una vez
Empezar de nuevo: Usuario quiere crear un nuevo carrito desde cero
Respuesta de error (400 - Parámetros faltantes):
{
"statusCode": 400,
"message": "Debe proporcionar requestId o cartId",
"date": 1754945173974,
"payload": {
"error": "MISSING_REQUIRED_PARAMETER"
}
}
Respuesta de error (400 - Producto no está en PENDING):
{
"statusCode": 500,
"message": "Product request is not pending",
"date": 1754945173974,
"payload": {
"error": "Product request is not pending"
}
}
Respuesta de error (400 - Carrito no está ACTIVE):
{
"statusCode": 500,
"message": "Cart is not active",
"date": 1754945173974,
"payload": {
"error": "Cart is not active"
}
}
Respuesta de error (404):
{
"statusCode": 500,
"message": "Product request not found",
"date": 1754945173974,
"payload": {
"error": "Product request not found"
}
}
💡 Tip para Testing:
Usa la variable {{lastCartId}} o {{lastRequestId}} que se llenan automáticamente al crear solicitudes.
Parámetros:
| Name | Type | Description | | --- | --- | --- | | requestId | string | Campo del body: requestId | | cartId | null | Campo del body: cartId |
products_banks_pse
Endpoints para crear pagos de productos
Obtiene la lista de bancos disponibles para pagos PSE.
📋 Uso:
Este endpoint es esencial para pagos PSE, ya que el usuario debe seleccionar su banco antes de crear el pago.
Headers requeridos:
Authorization: Bearer {token}x-secret-id: {secretId}
Respuesta exitosa (200):
Array de bancos con
id,nameeimageCada banco incluye el ID requerido para el campo
bankIden pagos PSE
Relación con otros endpoints:
El
iddel banco se usa endata.bankIddel endpointPOST /products-payment/createcuando el medio de pago es PSEdocumentType se debe asignar unas de estas opciones:
CC = Cedula de ciudadania
CE = Cedula de extranjeria
NIT = Nit
typePerson se debe asignar una de estas opciones:
0 = Natural
1 = Juridico
Ejemplo de uso en pago PSE:
{
"requestId": "uuid-request",
"id": 56, // ID del medio de pago PSE
"categoryid": 61,
"data": {
"bankId": "1007", // ID obtenido de este endpoint
"name": "Juan Perez",
"email": "[email protected]",
"cellphone": "3001234567",
"typePerson": "0",
"documentType": "CC",
"documentNumber": "1234567890"
}
}
products_payment_create
Endpoints para crear pagos de productos
Campo cartId (OBLIGATORIO): ID del carrito obtenido de
/product-requests/createFilosofía "Always Cart": Todos los productos (individuales o múltiples) usan carrito
Ejemplo correcto:
{
"cartId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"id": 304135,
"categoryid": 176,
"data": { "cellphone": "3051000002" },
"returnUrl": "https://mi-app.com/return",
"webhookUrl": "https://mi-app.com/webhook"
}
Crea el pago de un producto usando el medio de pago seleccionado. Esta es la etapa final del proceso de pago.
📋 Relación con Endpoint de Solicitud:
Los datos para crear este pago provienen de la respuesta del endpoint product-requests/create:
cartId: Del campocartIdde la respuesta del carritoid: Del campoiddel medio de pago seleccionadocategoryid: Del campocategoryiddel medio de pago seleccionadodata: Basado entemplate_data_requestdel medio de pago seleccionado
Headers requeridos:
Authorization: Bearer {token}x-secret-id: {secretId}
Body (JSON):
cartId(string, requerido): ID del carrito obtenido deproduct-requests/createid(number, requerido): ID del medio de pago seleccionadocategoryid(number, requerido): ID de la categoría del medio de pagodata(object, requerido): Datos del pagador basados entemplate_data_requestdel medio de pagoreturnUrl(string, requerido): URL de retorno después del pagowebhookUrl(string, requerido): URL para notificaciones de estado del pago
🔄 Flujo de Creación de Pago:
1. Respuesta de creación de solicitud:
{
"statusCode": 201,
"message": "Solicitud creada exitosamente",
"date": 1754945173974,
"payload": {
"cartId": "15974df4-a599-4d28-a2f2-bb5b8faa678b",
"requestId": "25884df4-a599-4d28-a2f2-bb5b8faa788a",
"amount": 9999,
"paymentMethods": [
{
"id": 304135,
"name": "Transfiya",
"internal_name": "AppFormTransfiya",
"description": "Transfiya",
"categoryid": 176,
"image": "transfiya.png",
"template_data_request": {
"cellphone": "3208888888"
}
},
{
"id": 56,
"name": "PSE",
"internal_name": "AppFormPse",
"description": "PSE",
"categoryid": 61,
"image": "pse.png",
"template_data_request": {
"name": "Juan Perez",
"email": "[email protected]",
"bankId": "1007",
"cellphone": "3208888888",
"typePerson": "0",
"documentType": "CC",
"documentNumber": "1032222222"
}
}
]
}
}
2. Crear pago con Transfiya (ejemplo):
{
"cartId": "15974df4-a599-4d28-a2f2-bb5b8faa678b",
"id": 304135,
"categoryid": 176,
"data": {
"cellphone": "3051000002"
},
"returnUrl": "https://plataforma.refacil.co/#/",
"webhookUrl": "https://webhook.site/4083efe6-7809-40ac-bbaa-9271d4a0c853"
}
3. Crear pago con PSE (ejemplo):
{
"cartId": "15974df4-a599-4d28-a2f2-bb5b8faa678b",
"id": 56,
"categoryid": 61,
"data": {
"name": "Juan Perez",
"email": "[email protected]",
"bankId": "1007",
"cellphone": "3051000002",
"typePerson": "0",
"documentType": "CC",
"documentNumber": "1032222222"
},
"returnUrl": "https://plataforma.refacil.co/#/",
"webhookUrl": "https://webhook.site/4083efe6-7809-40ac-bbaa-9271d4a0c853"
}
💳 Estructura de Datos por Medio de Pago:
Medios Simples (Solo celular):
Transfiya, Nequi, Daviplata
Campo data:
{"cellphone": "3051000002"}
Medios Bancarios (Datos completos):
PSE, Bancolombia
Campo data:
{"name", "email", "bankId", "cellphone", "typePerson", "documentType", "documentNumber"}
🔗 URLs de Configuración:
returnUrl: URL donde la pasarela de pago redirige al usuario después del pagowebhookUrl: URL donde se envían notificaciones de cambios de estado del pago
Respuesta exitosa (201):
{
"statusCode": 201,
"message": "Recurso de pago creado exitosamente",
"date": 1755026415574,
"payload": {
"cartId": "88d0b575-80f4-4f9b-af8f-5d09ec2cb877",
"url": "https://mf-core.refacil.co/refacilpay/resumen/62/5ff47b60-77b1-11f0-b5e9-6f43bd8928c1",
"reference": "5ff47b60-77b1-11f0-b5e9-6f43bd8928c1",
"amount": 19000,
"expiresIn": "2025-08-13T07:20:15.038Z"
}
}
📋 Datos de la Respuesta:
reference: Identificador único del pagourl: URL para redirigir al usuario al gateway de pagosamount: Monto a pagarcartId: ID del carrito que tiene las solicitudes de productos creadasexpiresIn: Fecha y hora de expiracion del recurso de pago
🔄 Siguiente Paso - Procesamiento:
Redirigir usuario: Usar
urlpara enviar al usuario al gateway de pagosProcesar pago: El usuario completa el pago en el gateway
Recibir notificaciones: El
webhookUrlrecibe actualizaciones de estadoRedirigir retorno: El usuario regresa a
returnUrldespués del pago
Respuesta de error (400):
{
"statusCode": 400,
"message": "Datos de entrada inválidos",
"date": 1754945173974,
"payload": {
"error": "INVALID_INPUT_DATA",
"details": "El campo data no coincide con el template del medio de pago"
}
}
Respuesta de error (404):
{
"statusCode": 404,
"message": "Solicitud no encontrada",
"date": 1754945173974,
"payload": {
"error": "REQUEST_NOT_FOUND",
"details": "La solicitud especificada no existe o ha expirado"
}
}
Respuesta de error (401):
{
"statusCode": 401,
"message": "Error de autenticación",
"date": 1754924521985,
"payload": {
"error": "AUTHENTICATION_ERROR",
"details": "Authentication failed",
"originalStatus": 401
}
}
Parámetros:
| Name | Type | Description |
| --- | --- | --- |
| cartId * | string | ID del carrito obtenido de product-requests/create |
| id * | number | ID del medio de pago seleccionado |
| categoryid * | number | ID de la categoría del medio de pago |
| data * | object | Datos del pagador basados en template_data_request del medio de pago |
| returnUrl * | string | URL de retorno después del pago |
| webhookUrl * | string | URL para notificaciones de estado del pago |
products_payment_retry_sale
Endpoints para crear pagos de productos
Reintenta la venta de un producto individual o todos los productos REFUNDED de un carrito.
⚠️ IMPORTANTE - Notificación Webhook:
Al realizar un reintento de venta, el sistema notificará automáticamente vía webhook el nuevo estado final del carrito después del reintento. Esto aplica tanto para requestId como para cartId.
📋 Parámetros:
Debes proporcionar uno de los siguientes parámetros:
requestId(string, opcional): ID único de la solicitud de producto en estado REFUNDED (UUID)cartId(string, opcional): ID único del carrito. Reintentará venta de todos los productos REFUNDED del carrito (UUID)
Headers requeridos:
Authorization: Bearer {token}x-secret-id: {secretId}
🔄 Flujo de Reintento:
1. Con requestId:
Valida que el producto esté en estado
REFUNDEDValida que el refund asociado esté en estado
REQUESTEDoFAILEDActualiza el refund a estado
PENDINGReintenta la venta del producto
Actualiza el refund según resultado:
RETRYCOMPLETED(venta exitosa) oFAILED(venta fallida)Notifica vía webhook el nuevo estado del carrito
2. Con cartId:
Busca todos los productos del carrito en estado
REFUNDEDPara cada producto, valida que el refund esté en estado
REQUESTEDoFAILEDReintenta la venta de cada producto válido
Notifica vía webhook el nuevo estado final del carrito completo
📊 Estados de Refund:
REQUESTED: Refund creado, listo para reintentoFAILED: Reintento anterior falló, puede reintentarsePENDING: Reintento en procesoRETRYCOMPLETED: Reintento exitoso, venta completadaCONFIRMED: Refund confirmado (no se puede reintentar)
🔔 Notificación Webhook:
Después del reintento, recibirás una notificación webhook con la estructura estándar de notificación de pago:
{
"cartId": "uuid-cart-id",
"reference": "topup-reference-123",
"status": "COMPLETED" | "PARTIALLY_REFUNDED" | "FULLY_REFUNDED",
"amount": 20000,
"products": [
{
"requestId": "uuid-request-1",
"status": "SOLD" | "REFUNDED" | "CANCELLED",
"amount": 10000
}
],
"timestamp": "2024-01-15T10:30:45.123Z",
"signature": "a1b2c3d4e5f6..."
}
Respuesta exitosa (200):
{
"statusCode": 200,
"message": "Reintento de venta procesado exitosamente",
"date": 1754945173974,
"payload": {
"requestId": "15974df4-a599-4d28-a2f2-bb5b8faa678b",
"cartId": "22884df4-a599-4d28-a2f2-bb5b8faa352b",
"status": "PROCESSED",
"message": "Reintento procesado. Se notificará vía webhook el estado final."
}
}
Respuesta de error (400):
{
"statusCode": 400,
"message": "Datos de entrada inválidos o producto no está en estado REFUNDED",
"date": 1754945173974,
"payload": {
"error": "INVALID_STATE",
"details": "El producto debe estar en estado REFUNDED y el refund en REQUESTED o FAILED"
}
}
Respuesta de error (404):
{
"statusCode": 404,
"message": "Producto o carrito no encontrado",
"date": 1754945173974,
"payload": {
"error": "NOT_FOUND"
}
}
💡 Tips:
Usa
{{lastRequestId}}o{{lastCartId}}para testing rápidoEl webhook se enviará al
webhookUrlconfigurado en el pago originalSi un producto del carrito no puede reintentarse (refund en estado inválido), se procesarán los demás productos
Los reintentos no generan nuevos refunds si ya existe uno para el
productRequestId
Parámetros:
| Name | Type | Description | | --- | --- | --- | | requestId | string | Campo del body: requestId | | cartId | string | Campo del body: cartId |
products_refund_create
Endpoints para crear reembolsos
Crea un reembolso para un request específico. Usado cuando un pago fue exitoso pero la venta falló.
Headers requeridos:
Authorization: Bearer {token}x-secret-id: {secretId}
Body (JSON):
requestId(string, requerido): ID del request a reembolsarkeyBreB(string, requerido): Clave BreB del cliente (número de celular u otro identificador)email(string, requerido): Email del clientewebhookUrl(string, requerido): URL para notificaciones del reembolso
Respuesta exitosa (201):
{
"statusCode": 201,
"message": "Refund creado exitosamente",
"date": 1704441600000,
"payload": {
"requestId": "0aaef286-867c-486d-bf98-3a16eeabad5c",
"reference": "00af1036-2473-4014-9c50-4d350ccc2560",
"keyBreB": "3051000002",
"amount": "9999.00"
}
}
Respuesta de error (400):
{
"statusCode": 400,
"message": "Datos de entrada inválidos",
"date": 1704441600000,
"payload": {
"error": "INVALID_REQUEST_ID",
"requestId": "req-uuid-1234-5678-9abc"
}
}
Respuesta de error (401):
{
"statusCode": 401,
"message": "Error de autenticación",
"date": 1754924521985,
"payload": {
"error": "AUTHENTICATION_ERROR",
"details": "Authentication failed",
"originalStatus": 401
}
}
Parámetros:
| Name | Type | Description | | --- | --- | --- | | requestId * | string | ID del request a reembolsar | | keyBreB * | string | Clave BreB del cliente (número de celular u otro identificador) | | email * | string | Email del cliente | | webhookUrl * | string | URL para notificaciones del reembolso |
dashboard_summary
Endpoints read-only para dashboards de cliente. Los siete POST /dashboard/* requieren autenticación (Bearer + x-secret-id) y filtran por el user_api_id del token. customer_id es obligatorio y mapea a core.product_requests.user_temp_id. El campo opcional subcustomer_id (string o null) se acepta en todas las rutas y mapea a core.product_requests.subcustomer_id: si se omite, es null o queda en blanco tras trim, no hay filtro por subcliente (todo el subsegmento bajo ese customer_id); si se envía, los resultados se limitan a ese subcliente. El rango from/to (ISO-8601 UTC) sigue las reglas de cada endpoint. Cada request documenta ambos patrones (con y sin subcustomer_id).
Devuelve KPIs agregados del cliente: totalRequests, totalSales, totalSalesAmount, totalRefunds, totalRefundsAmount, failedRequests, conversionRate (0..1).
Body:
customer_id(string, requerido)subcustomer_id(string, opcional) →core.product_requests.subcustomer_idfrom/to(ISO-8601 UTC, opcional; ambos o ninguno; from <= to)
Si no se envía rango, se aplican los últimos 30 días en UTC.
La pestaña Body incluye subcustomer_id y un rango de fechas explícito.
Ejemplo — sin filtro por subcliente (omite subcustomer_id):
{
"customer_id": "customer_123",
"from": "2026-03-01T00:00:00.000Z",
"to": "2026-03-31T23:59:59.000Z"
}Parámetros:
| Name | Type | Description | | --- | --- | --- | | customer_id | string | Campo del body: customer_id | | subcustomer_id | string | Campo del body: subcustomer_id | | from | string | Campo del body: from | | to | string | Campo del body: to |
dashboard_sales
Endpoints read-only para dashboards de cliente. Los siete POST /dashboard/* requieren autenticación (Bearer + x-secret-id) y filtran por el user_api_id del token. customer_id es obligatorio y mapea a core.product_requests.user_temp_id. El campo opcional subcustomer_id (string o null) se acepta en todas las rutas y mapea a core.product_requests.subcustomer_id: si se omite, es null o queda en blanco tras trim, no hay filtro por subcliente (todo el subsegmento bajo ese customer_id); si se envía, los resultados se limitan a ese subcliente. El rango from/to (ISO-8601 UTC) sigue las reglas de cada endpoint. Cada request documenta ambos patrones (con y sin subcustomer_id).
Listado paginado de ventas exitosas (product_sales.status = SUCCESS) enriquecido con datos del product_request.
Body adicional:
subcustomer_id(opcional) →core.product_requests.subcustomer_idpage(default 1, min 1)limit(default 20, max 100)product_type(opcional)
Filtro de fechas: COALESCE(executed_at, created_at) de la venta.
La pestaña Body trae un ejemplo con subcustomer_id para que se vea directo en la colección.
Ejemplo — todo el segmento de customer_id (sin subcustomer_id o null):
{
"customer_id": "customer_123",
"page": 1,
"limit": 20,
"product_type": "RECARGA"
}Parámetros:
| Name | Type | Description | | --- | --- | --- | | customer_id | string | Campo del body: customer_id | | subcustomer_id | string | Campo del body: subcustomer_id | | page | number | Campo del body: page | | limit | number | Campo del body: limit | | product_type | string | Campo del body: product_type |
dashboard_transactions
Endpoints read-only para dashboards de cliente. Los siete POST /dashboard/* requieren autenticación (Bearer + x-secret-id) y filtran por el user_api_id del token. customer_id es obligatorio y mapea a core.product_requests.user_temp_id. El campo opcional subcustomer_id (string o null) se acepta en todas las rutas y mapea a core.product_requests.subcustomer_id: si se omite, es null o queda en blanco tras trim, no hay filtro por subcliente (todo el subsegmento bajo ese customer_id); si se envía, los resultados se limitan a ese subcliente. El rango from/to (ISO-8601 UTC) sigue las reglas de cada endpoint. Cada request documenta ambos patrones (con y sin subcustomer_id).
Listado paginado de product_requests con el estado consolidado del flujo (request + payment + topup + sale). Filtros opcionales: status (array de ProductRequestStatus) y product_type. subcustomer_id opcional → core.product_requests.subcustomer_id.
La pestaña Body incluye subcustomer_id para que el campo se vea en la colección.
Ejemplo — sin filtro por subcliente (omite subcustomer_id):
{
"customer_id": "customer_123",
"page": 1,
"limit": 20,
"status": ["SOLD", "REFUNDED"],
"product_type": "FACTURA"
}Parámetros:
| Name | Type | Description | | --- | --- | --- | | customer_id | string | Campo del body: customer_id | | subcustomer_id | string | Campo del body: subcustomer_id | | page | number | Campo del body: page | | limit | number | Campo del body: limit | | status | array | Campo del body: status | | product_type | string | Campo del body: product_type |
dashboard_stats_by_status
Endpoints read-only para dashboards de cliente. Los siete POST /dashboard/* requieren autenticación (Bearer + x-secret-id) y filtran por el user_api_id del token. customer_id es obligatorio y mapea a core.product_requests.user_temp_id. El campo opcional subcustomer_id (string o null) se acepta en todas las rutas y mapea a core.product_requests.subcustomer_id: si se omite, es null o queda en blanco tras trim, no hay filtro por subcliente (todo el subsegmento bajo ese customer_id); si se envía, los resultados se limitan a ese subcliente. El rango from/to (ISO-8601 UTC) sigue las reglas de cada endpoint. Cada request documenta ambos patrones (con y sin subcustomer_id).
Agrupa product_requests por ProductRequestStatus. La respuesta SIEMPRE incluye una entrada por cada estado del enum (count=0, totalAmount=0 si no hay registros). subcustomer_id opcional → core.product_requests.subcustomer_id.
La pestaña Body incluye subcustomer_id.
Ejemplo — sin filtro por subcliente:
{
"customer_id": "customer_123"
}Parámetros:
| Name | Type | Description | | --- | --- | --- | | customer_id | string | Campo del body: customer_id | | subcustomer_id | string | Campo del body: subcustomer_id |
dashboard_stats_by_product_type
Endpoints read-only para dashboards de cliente. Los siete POST /dashboard/* requieren autenticación (Bearer + x-secret-id) y filtran por el user_api_id del token. customer_id es obligatorio y mapea a core.product_requests.user_temp_id. El campo opcional subcustomer_id (string o null) se acepta en todas las rutas y mapea a core.product_requests.subcustomer_id: si se omite, es null o queda en blanco tras trim, no hay filtro por subcliente (todo el subsegmento bajo ese customer_id); si se envía, los resultados se limitan a ese subcliente. El rango from/to (ISO-8601 UTC) sigue las reglas de cada endpoint. Cada request documenta ambos patrones (con y sin subcustomer_id).
Agrupa por product_type. Por defecto solo status=SOLD. Acepta statuses (array) para overridear. subcustomer_id opcional → core.product_requests.subcustomer_id.
La pestaña Body incluye subcustomer_id.
Ejemplo — sin filtro por subcliente:
{
"customer_id": "customer_123",
"statuses": ["SOLD"]
}Parámetros:
| Name | Type | Description | | --- | --- | --- | | customer_id | string | Campo del body: customer_id | | subcustomer_id | string | Campo del body: subcustomer_id | | statuses | array | Campo del body: statuses |
dashboard_stats_timeseries
Endpoints read-only para dashboards de cliente. Los siete POST /dashboard/* requieren autenticación (Bearer + x-secret-id) y filtran por el user_api_id del token. customer_id es obligatorio y mapea a core.product_requests.user_temp_id. El campo opcional subcustomer_id (string o null) se acepta en todas las rutas y mapea a core.product_requests.subcustomer_id: si se omite, es null o queda en blanco tras trim, no hay filtro por subcliente (todo el subsegmento bajo ese customer_id); si se envía, los resultados se limitan a ese subcliente. El rango from/to (ISO-8601 UTC) sigue las reglas de cada endpoint. Cada request documenta ambos patrones (con y sin subcustomer_id).
Serie temporal de ventas SOLD agrupada por granularity (day | month, default day). Buckets vacíos vienen con count=0 y totalAmount=0. subcustomer_id opcional → core.product_requests.subcustomer_id.
La pestaña Body incluye subcustomer_id.
Ejemplo — todos los subsegmentos en el rango (omite subcustomer_id):
{
"customer_id": "customer_123",
"granularity": "day",
"from": "2026-03-01T00:00:00.000Z",
"to": "2026-03-07T23:59:59.000Z"
}Parámetros:
| Name | Type | Description | | --- | --- | --- | | customer_id | string | Campo del body: customer_id | | subcustomer_id | string | Campo del body: subcustomer_id | | granularity | string | Campo del body: granularity | | from | string | Campo del body: from | | to | string | Campo del body: to |
dashboard_refunds
Endpoints read-only para dashboards de cliente. Los siete POST /dashboard/* requieren autenticación (Bearer + x-secret-id) y filtran por el user_api_id del token. customer_id es obligatorio y mapea a core.product_requests.user_temp_id. El campo opcional subcustomer_id (string o null) se acepta en todas las rutas y mapea a core.product_requests.subcustomer_id: si se omite, es null o queda en blanco tras trim, no hay filtro por subcliente (todo el subsegmento bajo ese customer_id); si se envía, los resultados se limitan a ese subcliente. El rango from/to (ISO-8601 UTC) sigue las reglas de cada endpoint. Cada request documenta ambos patrones (con y sin subcustomer_id).
Listado paginado de reembolsos del customer con datos del product_request asociado. Filtro opcional status (array). subcustomer_id opcional → core.product_requests.subcustomer_id. Filtro de fechas sobre refunds.created_at.
La pestaña Body incluye subcustomer_id.
Ejemplo — sin filtro por subcliente:
{
"customer_id": "customer_123",
"page": 1,
"limit": 20,
"status": ["CONFIRMED"]
}Parámetros:
| Name | Type | Description | | --- | --- | --- | | customer_id | string | Campo del body: customer_id | | subcustomer_id | string | Campo del body: subcustomer_id | | page | number | Campo del body: page | | limit | number | Campo del body: limit | | status | array | Campo del body: status |
about_webhook_guide
Guía para implementar webhooks del lado del cliente para recibir notificaciones de pagos y reembolsos
⚠️ ESTE ITEM NO ES UN ENDPOINT EJECUTABLE DE LA API.
Es una referencia informativa para integradores. La URL about:client-webhook-guide se usa a propósito para evitar que Postman lo ejecute como request HTTP del microservicio (no generará 404 contra el API). El contenido debe leerse solo como guía.
📋 IMPORTANTE: Implementación de Webhooks del Cliente Requerida
Este NO es un endpoint de la API, sino una guía para implementar webhooks en TU sistema.
🔄 Lo que Necesitas Implementar:
Para recibir notificaciones de estado de pagos y reembolsos, DEBES implementar endpoints webhook en tu sistema:
1. Webhook de Estado de Pago
URL: Tu endpoint (ej.,
https://tu-dominio.com/webhooks/estado-pago)Método: POST
Propósito: Recibir actualizaciones de estado de pago (SOLD, REFUNDED, CANCELLED)
2. Webhook de Estado de Reembolso
URL: Tu endpoint (ej.,
https://tu-dominio.com/webhooks/estado-reembolso)Método: POST
Propósito: Recibir actualizaciones de estado de reembolso (CONFIRMED, FAILED)
🔑 Cómo Configurar:
Implementa endpoints webhook en tu sistema
Proporciona las URLs en el campo
webhookUrlal crear pagos/reembolsosValida las firmas usando HMAC-SHA1 y tu
hashKey
📚 Documentación Disponible:
Guía de Webhooks del Cliente:
client-webhook-documentation.md Solicitar a soporte si es necesarioEjemplos de Código:
webhook-examples.md Solicitar a soporte si es necesarioValidación de Firmas: Algoritmo HMAC-SHA1
⚠️ Requisitos de Seguridad:
Tu webhook debe responder con HTTP 200-299 en menos de 10 segundos
Valida el campo
signatureusando HMAC-SHA1
