Diferencia entre revisiones de «API Modulo Forms»

De WikiSerpi
Ir a la navegación Ir a la búsqueda
v1
Sin resumen de edición
Línea 1: Línea 1:


= SERPI Forms Core API (v1) =
= SERPI Forms Core API (v1) =


== Categorías y Roles ==
== Descripción ==
El microservicio '''SERPI Forms''' proporciona almacenamiento, renderizado y análisis histórico de respuestas para formularios dinámicos. Opera bajo una arquitectura multi-tenant y se integra de forma nativa con el ERP SERPI, permitiendo a las empresas gestionar encuestas, auditorías y captura de datos en terreno.
 
== Autorización ==
La API utiliza un esquema de seguridad basado en tokens JWT (Bearer Token). Para acceder a los endpoints protegidos, debes incluir el token en las cabeceras HTTP de tu petición:<source lang="http">
Authorization: Bearer <TOKEN_JWT>
</source>> '''Nota de Desarrollo:''' Si el bypass de desarrollo local está habilitado, se puede utilizar el encabezado `X-Empresa-Id: <ID>` en lugar del JWT.
 
== Beneficio ==
 
* '''Trazabilidad y Auditoría:''' Inmutabilidad de respuestas en el histórico y captura automática de la IP de origen (`ip_origen`).
* '''Aislamiento de Datos (Multi-Tenant):''' Despliegue de bases de datos dedicadas por cliente para máxima seguridad.
* '''Flexibilidad Estructural:''' Modelo híbrido Relacional/JSON que ofrece compatibilidad instantánea con motores de Inteligencia de Negocios (BI).
 
== Tipos de peticiones ==
El API sigue los estándares RESTful utilizando los siguientes métodos HTTP:
 
* '''GET:''' Recuperar información (ej. listar formularios, consultar carpetas o métricas).
* '''POST:''' Crear nuevos recursos en el sistema o enviar respuestas públicas.
* '''PUT:''' Actualizar recursos existentes, reubicar carpetas o cambiar estados (activo/inactivo).
* '''DELETE:''' Ejecutar eliminaciones lógicas (soft-delete) o físicas de recursos protegidos.
 
== ¿Cómo funciona? ==
El ciclo de vida transaccional en SERPI Forms consta de los siguientes pasos:
 
# '''Configuración y Organización:''' Se crean ''Categorías'' (con reglas de roles) y ''Carpetas'' para organizar el entorno (Workspace).
# '''Diseño del Formulario:''' Se registra el esquema dinámico JSON que define las preguntas y lógicas del formulario.
# '''Distribución:''' Se generan URLs públicas o se habilitan para consultas en tiempo real durante visitas comerciales (aplicando reglas de frecuencia).
# '''Recolección:''' El encuestado diligencia los datos, impactando el endpoint público que registra la respuesta y orquesta el cobro SaaS (folios).
# '''Análisis:''' Se consultan los indicadores globales y el histórico de respuestas a través de los endpoints de gestión.
 
---
 
== ⚡ Referencia de Endpoints ==
<tabber> Categorías y Roles=


=== GET /api/v1/categories ===
=== GET /api/v1/categories ===
'''Ruta y Método HTTP:'''<source lang="http">
Devuelve un listado completo de todas las categorías configuradas en el sistema para la empresa del usuario autenticado. Las categorías permiten organizar formularios y establecer políticas de acceso basado en roles (RBAC).
GET /api/v1/categories HTTP/1.1
 
Host: api.serpi.com.co
* '''Ruta y Método:''' <code>GET /api/v1/categories</code>
Authorization: Bearer <TOKEN_JWT>
</source>'''Descripción:''' Devuelve un listado completo de todas las categorías configuradas en el sistema para la empresa del usuario autenticado. Las categorías permiten organizar formularios y establecer políticas de aislamiento y acceso basado en roles (RBAC).


'''Parámetros esperados:'''
==== Respuesta Exitosa (200 OK) ====
{| class="wikitable"
<source lang="json">
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|''Ninguno''
|N/A
|No
|Este endpoint no requiere parámetros de consulta (Query) ni de ruta (Path).
|}
'''Ejemplo de Respuesta Exitosa (Código 200 OK):'''<source lang="json">
[
[
   {
   {
Línea 30: Línea 51:
     "color": "#3B82F6",
     "color": "#3B82F6",
     "roleIds": [101, 102]
     "roleIds": [101, 102]
  },
  {
    "categoriaId": 2,
    "nombre": "Auditorías de Visitas",
    "color": "#10B981",
    "roleIds": []
   }
   }
]
]
</source>'''Códigos de Error Posibles:'''
</source>


* '''401 Unauthorized''': Token JWT ausente, expirado o inválido.
* '''Errores posibles:''' <code>401 Unauthorized</code>, <code>403 Forbidden</code>
* '''403 Forbidden''': El rol del usuario no tiene permisos para consultar categorías.


----
=== POST /api/v1/categories ===
Registra una nueva categoría en el sistema.


=== GET /api/v1/categories/{id} ===
* '''Ruta y Método:''' <code>POST /api/v1/categories</code>
'''Ruta y Método HTTP:'''<source lang="http">
GET /api/v1/categories/1 HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
</source>'''Descripción:''' Busca y devuelve los detalles de una categoría específica utilizando su identificador único numérico.


'''Parámetros esperados:'''
==== Parámetros ====
{| class="wikitable"
{| class="wikitable"
!Nombre del Parámetro
!Parámetro
!Tipo
!Tipo
!Obligatorio
!Obligatorio
!Descripción
!Descripción
|-
|-
|id
|Body
|Integer
|Sí (Path)
|Identificador único numérico de la categoría a consultar.
|}
'''Ejemplo de Respuesta Exitosa (Código 200 OK):'''<source lang="json">
{
  "categoriaId": 1,
  "nombre": "Encuestas de Satisfacción",
  "color": "#3B82F6",
  "roleIds": [101, 102]
}
</source>'''Códigos de Error Posibles:'''
 
* '''401 Unauthorized''': No autenticado.
* '''403 Forbidden''': Permisos insuficientes.
* '''404 Not Found''': El ID especificado no corresponde a ninguna categoría activa.
 
----
 
=== POST /api/v1/categories ===
'''Ruta y Método HTTP:'''<source lang="http">
POST /api/v1/categories HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
Content-Type: application/json
</source>'''Descripción:''' Registra una nueva categoría en el sistema especificando su nombre, color representativo en formato hexadecimal y de forma opcional los roles permitidos.
 
'''Parámetros esperados:'''
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|''Body''
|Object
|Object
|Sí
|Sí
|Objeto JSON con los datos de creación de la categoría.
|Objeto JSON con nombre, color hexadecimal y roleIds.
|}
|}
'''Ejemplo de Payload / Body:'''<source lang="json">
 
==== Payload y Respuesta (201 Created) ====
<source lang="json">
{
{
   "nombre": "Control de Calidad",
   "nombre": "Control de Calidad",
Línea 105: Línea 82:
   "roleIds": [105, 108]
   "roleIds": [105, 108]
}
}
</source>'''Ejemplo de Respuesta Exitosa (Código 201 Created):'''<source lang="json">
</source>
{
  "categoriaId": 3,
  "nombre": "Control de Calidad",
  "color": "#F59E0B",
  "roleIds": [105, 108]
}
</source>'''Códigos de Error Posibles:'''
 
* '''400 Bad Request''': Error de validación en el payload (nombre vacío o color hexadecimal inválido).
* '''401 Unauthorized''': No autenticado.
* '''403 Forbidden''': El perfil del usuario no permite crear categorías.
 
----
 
=== PUT /api/v1/categories/{id} ===
'''Ruta y Método HTTP:'''<source lang="http">
PUT /api/v1/categories/3 HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
Content-Type: application/json
</source>'''Descripción:''' Actualiza las propiedades de una categoría existente (nombre, color representativo o lista de roles autorizados).
 
'''Parámetros esperados:'''
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|id
|Integer
|Sí (Path)
|ID numérico de la categoría a actualizar.
|-
|''Body''
|Object
|Sí
|Objeto JSON con los nuevos valores de la categoría.
|}
'''Ejemplo de Payload / Body:'''<source lang="json">
{
  "nombre": "Control de Calidad y Procesos",
  "color": "#EF4444",
  "roleIds": [105, 108, 110]
}
</source>'''Ejemplo de Respuesta Exitosa (Código 204 No Content):'''<source lang="http">
HTTP/1.1 204 No Content
</source>'''Códigos de Error Posibles:'''
 
* '''400 Bad Request''': Datos de entrada no cumplen los criterios de validación.
* '''401 Unauthorized''': No autenticado.
* '''403 Forbidden''': Permisos insuficientes.
* '''404 Not Found''': Categoría no encontrada.
 
----
 
=== DELETE /api/v1/categories/{id} ===
'''Ruta y Método HTTP:'''<source lang="http">
DELETE /api/v1/categories/3 HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
</source>'''Descripción:''' Elimina de forma física y permanente una categoría. La operación fallará si la categoría posee carpetas activas para proteger la integridad estructural.


'''Parámetros esperados:'''
=== PUT y DELETE /api/v1/categories/{id} ===
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|id
|Integer
|Sí (Path)
|ID numérico de la categoría a eliminar.
|}
'''Ejemplo de Respuesta Exitosa (Código 204 No Content):'''<source lang="http">
HTTP/1.1 204 No Content
</source>'''Códigos de Error Posibles:'''
 
* '''401 Unauthorized''': No autenticado.
* '''403 Forbidden''': Permisos insuficientes.
* '''404 Not Found''': La categoría no existe o ya fue eliminada.


----
* '''PUT:''' Actualiza las propiedades de una categoría existente. Retorna <code>204 No Content</code>.
* '''DELETE:''' Elimina de forma física una categoría (falla si posee carpetas activas). Retorna <code>204 No Content</code>.


=== GET /api/v1/categories/roles ===
=== GET /api/v1/categories/roles ===
'''Ruta y Método HTTP:'''<source lang="http">
Recupera todos los roles y perfiles configurados en la base de datos maestra del ERP (MvcSERPI) para la empresa actual.
GET /api/v1/categories/roles HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
</source>'''Descripción:''' Recupera todos los roles y perfiles configurados en la base de datos maestra del ERP (MvcSERPI) para la empresa actual, facilitando la asignación granular de permisos.


'''Parámetros esperados:'''
* '''Ruta y Método:''' <code>GET /api/v1/categories/roles</code>
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|''Ninguno''
|N/A
|No
|No requiere parámetros.
|}
'''Ejemplo de Respuesta Exitosa (Código 200 OK):'''<source lang="json">
[
  {
    "rolId": 101,
    "nombre": "Administrador de Ventas"
  },
  {
    "rolId": 102,
    "nombre": "Asesor Comercial"
  }
]
</source>'''Códigos de Error Posibles:'''


* '''401 Unauthorized''': No autenticado.
|-| Carpetas y Workspace=
* '''403 Forbidden''': Sin acceso a configuraciones de seguridad.


----
=== GET /api/v1/folders ===
Retorna la estructura jerárquica completa de carpetas, subcarpetas y formularios, filtrada automáticamente por los roles del usuario.


== Carpetas y Workspace ==
* '''Ruta y Método:''' <code>GET /api/v1/folders</code>


=== GET /api/v1/folders ===
==== Respuesta Exitosa (200 OK) ====
'''Ruta y Método HTTP:'''<source lang="http">
<source lang="json">
GET /api/v1/folders HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
</source>'''Descripción:''' Retorna la estructura jerárquica completa de carpetas, subcarpetas y formularios contenidos dentro del Workspace, filtrada de forma automática por los roles del usuario.
 
'''Parámetros esperados:'''
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|''Ninguno''
|N/A
|No
|No requiere parámetros.
|}
'''Ejemplo de Respuesta Exitosa (Código 200 OK):'''<source lang="json">
[
[
   {
   {
Línea 257: Línea 110:
     "categoriaId": 1,
     "categoriaId": 1,
     "color": "#3B82F6",
     "color": "#3B82F6",
     "children": [
     "children": [],
      {
     "forms": []
        "id": "folder_12",
        "name": "Zonales",
        "parentId": "folder_10",
        "categoriaId": 1,
        "color": "#3B82F6"
      }
    ],
     "forms": [
      {
        "uuid": "8f3b2a1c-9e4d-4c8a-b5f6-7d8e9f0a1b2c",
        "titulo": "Evaluación de Servicio en Tienda",
        "activo": true
      }
    ]
   }
   }
]
]
</source>'''Códigos de Error Posibles:'''
</source>
 
* '''401 Unauthorized''': Se requiere sesión activa.
 
----


=== POST /api/v1/folders ===
=== POST /api/v1/folders ===
'''Ruta y Método HTTP:'''<source lang="http">
Crea una nueva carpeta en la raíz o como subcarpeta.
POST /api/v1/folders HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
Content-Type: application/json
</source>'''Descripción:''' Crea una nueva carpeta en la raíz del entorno o como subcarpeta (indicando <code>parentId</code>). Requiere estar vinculada a una categoría existente.


'''Parámetros esperados:'''
* '''Ruta y Método:''' <code>POST /api/v1/folders</code>
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|''Body''
|Object
|Sí
|Datos para la creación de la carpeta.
|}
'''Ejemplo de Payload / Body:'''<source lang="json">
{
  "name": "Encuestas Region Andina",
  "parentId": "folder_10",
  "categoriaId": 1
}
</source>'''Ejemplo de Respuesta Exitosa (Código 201 Created):'''<source lang="json">
{
  "id": "folder_25",
  "name": "Encuestas Region Andina",
  "parentId": "folder_10",
  "categoriaId": 1,
  "color": "#3B82F6",
  "children": [],
  "forms": []
}
</source>'''Códigos de Error Posibles:'''
 
* '''400 Bad Request''': Nombre inválido o categoría inexistente.
* '''401 Unauthorized''': No autenticado.
 
----
 
=== PUT /api/v1/folders/{id} ===
'''Ruta y Método HTTP:'''<source lang="http">
PUT /api/v1/folders/25 HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
Content-Type: application/json
</source>'''Descripción:''' Renombra o mueve una carpeta existente dentro del árbol del Workspace.


'''Parámetros esperados:'''
==== Parámetros ====
{| class="wikitable"
{| class="wikitable"
!Nombre del Parámetro
!Parámetro
!Tipo
!Tipo
!Obligatorio
!Obligatorio
!Descripción
!Descripción
|-
|-
|id
|Body
|Integer
|Sí (Path)
|ID numérico de la carpeta a modificar.
|-
|''Body''
|Object
|Object
|Sí
|Sí
|Datos actualizados de la carpeta.
|Datos de la carpeta (name, parentId, categoriaId).
|}
|}
'''Ejemplo de Payload / Body:'''<source lang="json">
{
  "nombre": "Encuestas Región Andina y Centro",
  "parentId": null
}
</source>'''Ejemplo de Respuesta Exitosa (Código 204 No Content):'''<source lang="http">
HTTP/1.1 204 No Content
</source>'''Códigos de Error Posibles:'''


* '''400 Bad Request''': Intento de mover una carpeta dentro de sí misma o nombre nulo.
=== PUT y DELETE /api/v1/folders/{id} ===
* '''401 Unauthorized''': Sin sesión activa.
* '''404 Not Found''': Carpeta no encontrada.


----
* '''PUT:''' Renombra o mueve una carpeta existente. Retorna <code>204 No Content</code>.
* '''DELETE:''' Borrado lógico en cascada de una carpeta y sus dependencias. Retorna <code>204 No Content</code>.


=== GET /api/v1/folders/{id}/history ===
=== GET /api/v1/folders/{id}/history ===
'''Ruta y Método HTTP:'''<source lang="http">
Obtiene la bitácora de auditoría histórica de eventos sobre la carpeta (creación, renombramiento, etc).
GET /api/v1/folders/25/history HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
</source>'''Descripción:''' Obtiene la bitácora de auditoría histórica de eventos sobre la carpeta especificada (creación, cambio de nombre, movimientos).


'''Parámetros esperados:'''
|-| Formularios Dinámicos=
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|id
|Integer
|Sí (Path)
|ID numérico de la carpeta a consultar.
|}
'''Ejemplo de Respuesta Exitosa (Código 200 OK):'''<source lang="json">
[
  {
    "auditoriaId": 501,
    "entidad": "carpeta",
    "entidadId": "25",
    "accion": "crear",
    "detalle": "Carpeta creada con nombre 'Encuestas Region Andina'",
    "usuarioId": 12,
    "fecha": "2026-08-21T07:00:00Z"
  },
  {
    "auditoriaId": 508,
    "entidad": "carpeta",
    "entidadId": "25",
    "accion": "renombrar",
    "detalle": "Carpeta renombrada a 'Encuestas Región Andina y Centro'",
    "usuarioId": 12,
    "fecha": "2026-08-21T07:10:00Z"
  }
]
</source>'''Códigos de Error Posibles:'''


* '''401 Unauthorized''': No autorizado.
=== POST /api/v1/forms ===
Crea un nuevo formulario dinámico asociando su esquema JSON y retornando un UUID no secuencial para la URL pública.


----
* '''Ruta y Método:''' <code>POST /api/v1/forms</code>


=== DELETE /api/v1/folders/{id} ===
==== Parámetros ====
'''Ruta y Método HTTP:'''<source lang="http">
DELETE /api/v1/folders/25 HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
</source>'''Descripción:''' Realiza un borrado lógico en cascada de una carpeta y de todas sus subcarpetas y formularios dependientes.
 
'''Parámetros esperados:'''
{| class="wikitable"
{| class="wikitable"
!Nombre del Parámetro
!Parámetro
!Tipo
!Tipo
!Obligatorio
!Obligatorio
!Descripción
!Descripción
|-
|-
|id
|Body
|Integer
|Sí (Path)
|ID de la carpeta a eliminar.
|}
'''Ejemplo de Respuesta Exitosa (Código 204 No Content):'''<source lang="http">
HTTP/1.1 204 No Content
</source>'''Códigos de Error Posibles:'''
 
* '''400 Bad Request''': Error en el proceso de eliminación lógica.
* '''401 Unauthorized''': No autorizado.
* '''404 Not Found''': Carpeta no encontrada.
 
----
 
== Formularios Dinámicos ==
 
=== POST /api/v1/forms ===
'''Ruta y Método HTTP:'''<source lang="http">
POST /api/v1/forms HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
Content-Type: application/json
</source>'''Descripción:''' Crea un nuevo formulario dinámico asociando su esquema JSON y retornando un UUID no secuencial para la URL pública.
 
'''Parámetros esperados:'''
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|''Body''
|Object
|Object
|Sí
|Sí
|Datos requeridos para la plantilla de formulario.
|Payload con nombre, título, descripción, carpetaId y esquemaJson.
|}
|}
'''Ejemplo de Payload / Body:'''<source lang="json">
 
{
==== Respuesta Exitosa (201 Created) ====
  "nombre": "Encuesta Visita Cliente",
<source lang="json">
  "titulo": "Encuesta de Satisfacción en Visita",
  "descripcion": "Formulario diligenciado en visitas comerciales.",
  "carpetaId": 25,
  "esquemaJson": "{\"settings\":{\"contexto\":\"Cliente\",\"repeatFrequency\":\"1w\"},\"components\":[]}"
}
</source>'''Ejemplo de Respuesta Exitosa (Código 201 Created):'''<source lang="json">
{
{
   "formId": 45,
   "formId": 45,
Línea 476: Línea 170:
   "urlPublica": "/f/15/d3b07384-d113-4f4a-a62e-336712345678"
   "urlPublica": "/f/15/d3b07384-d113-4f4a-a62e-336712345678"
}
}
</source>'''Códigos de Error Posibles:'''
</source>


* '''400 Bad Request''': Esquema JSON o campos obligatorios faltantes/mal formateados.
=== Endpoints de Gestión de Formularios ===
* '''401 Unauthorized''': No autenticado.


----
* '''PUT /api/v1/forms/{uuid}:''' Actualiza esquema JSON y detalles.
* '''DELETE /api/v1/forms/{uuid}:''' Borrado lógico (Soft Delete) hacia la papelera.
* '''PUT /api/v1/forms/{uuid}/toggle-status:''' Activa o desactiva el formulario.
* '''PUT /api/v1/forms/{uuid}/move?carpetaId={id}:''' Reubica el formulario en otra carpeta.
* '''GET /api/v1/forms/{uuid}/history:''' Auditoría cronológica de modificaciones.
* '''PUT /api/v1/forms/{uuid}/restore:''' Restaura un formulario desde la papelera.


=== PUT /api/v1/forms/{uuid} ===
=== Endpoints de Respuestas y Métricas ===
'''Ruta y Método HTTP:'''<source lang="http">
PUT /api/v1/forms/d3b07384-d113-4f4a-a62e-336712345678 HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
Content-Type: application/json
</source>'''Descripción:''' Actualiza el título, descripción y estructura de preguntas (Esquema JSON) de un formulario existente.


'''Parámetros esperados:'''
* '''GET /api/v1/forms/stats:''' Devuelve KPIs globales (respuestasHoy, respuestasTotal, formulariosActivos).
{| class="wikitable"
* '''GET /api/v1/forms/{formId}/responses:''' Listado detallado de respuestas (soporta startDate y endDate).
!Nombre del Parámetro
* '''GET /api/v1/forms/{formId}/responses/count:''' Conteo numérico total de respuestas.
!Tipo
!Obligatorio
!Descripción
|-
|uuid
|String
|Sí (Path)
|UUID del formulario a actualizar.
|-
|''Body''
|Object
|Sí
|Datos actualizados del formulario.
|}
'''Ejemplo de Payload / Body:'''<source lang="json">
{
  "nombre": "Encuesta Visita Cliente v2",
  "titulo": "Encuesta de Satisfacción Comercial v2",
  "descripcion": "Formulario actualizado para atención a clientes.",
  "esquemaJson": "{\"settings\":{\"contexto\":\"Cliente\",\"repeatFrequency\":\"1d\"},\"components\":[]}"
}
</source>'''Ejemplo de Respuesta Exitosa (Código 204 No Content):'''<source lang="http">
HTTP/1.1 204 No Content
</source>'''Códigos de Error Posibles:'''


* '''400 Bad Request''': Errores estructurales en el JSON enviado.
=== Disponibilidad y Terceros ===
* '''401 Unauthorized''': No autenticado.
* '''404 Not Found''': Formulario no encontrado por el UUID.


----
* '''GET /api/v1/forms/surveys/available:''' Evalúa encuestas disponibles para un tercero, aplicando reglas anti-spam.
* '''POST /api/v1/forms/terceros/verificar:''' Valida registros activos en <code>gdttercero</code> enviando un arreglo de NITs.


=== DELETE /api/v1/forms/{uuid} ===
|-| Público, SaaS y Empresa=
'''Ruta y Método HTTP:'''<source lang="http">
DELETE /api/v1/forms/d3b07384-d113-4f4a-a62e-336712345678 HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
</source>'''Descripción:''' Ejecuta un borrado lógico (Soft Delete) del formulario, desactivándolo y moviéndolo a la papelera sin perder respuestas históricas. Requiere estar apagado previamente.


'''Parámetros esperados:'''
=== GET /api/v1/forms/public/{empresaid}/{uuid} ===
{| class="wikitable"
Devuelve el esquema y diseño público de un formulario para renderizarse en el frontend. (No requiere JWT).
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|uuid
|String
|Sí (Path)
|UUID del formulario a enviar a la papelera.
|}
'''Ejemplo de Respuesta Exitosa (Código 204 No Content):'''<source lang="http">
HTTP/1.1 204 No Content
</source>'''Códigos de Error Posibles:'''
 
* '''400 Bad Request''': El formulario está Activo. Debe desactivarse antes de eliminarse.
* '''401 Unauthorized''': No autenticado.
* '''404 Not Found''': Formulario inexistente.
 
----
 
=== PUT /api/v1/forms/{uuid}/toggle-status ===
'''Ruta y Método HTTP:'''<source lang="http">
PUT /api/v1/forms/d3b07384-d113-4f4a-a62e-336712345678/toggle-status HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
Content-Type: application/json
</source>'''Descripción:''' Alterna el estado de un formulario entre Activo (disponible públicamente) e Inactivo (bloquea la recepción de respuestas).
 
'''Parámetros esperados:'''
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|uuid
|String
|Sí (Path)
|UUID del formulario a modificar.
|-
|''Body''
|Object
|Sí
|Indicador de estado (<code>activo</code>: true/false).
|}
'''Ejemplo de Payload / Body:'''<source lang="json">
{
  "activo": false
}
</source>'''Ejemplo de Respuesta Exitosa (Código 204 No Content):'''<source lang="http">
HTTP/1.1 204 No Content
</source>'''Códigos de Error Posibles:'''
 
* '''401 Unauthorized''': Sin autorización.
* '''404 Not Found''': Formulario no encontrado.
 
----
 
=== PUT /api/v1/forms/{uuid}/move ===
'''Ruta y Método HTTP:'''<source lang="http">
PUT /api/v1/forms/d3b07384-d113-4f4a-a62e-336712345678/move?carpetaId=25 HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
</source>'''Descripción:''' Reubica un formulario en otra carpeta contenedora o en la raíz del Workspace (si se omite el parámetro <code>carpetaId</code>).
 
'''Parámetros esperados:'''
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|uuid
|String
|Sí (Path)
|UUID del formulario a mover.
|-
|carpetaId
|Integer
|No (Query)
|ID de la carpeta destino (omitir para mover a la raíz).
|}
'''Ejemplo de Respuesta Exitosa (Código 204 No Content):'''<source lang="http">
HTTP/1.1 204 No Content
</source>'''Códigos de Error Posibles:'''
 
* '''401 Unauthorized''': No autenticado.
* '''404 Not Found''': Formulario o carpeta destino no encontrados.
 
----
 
=== GET /api/v1/forms/{uuid}/history ===
'''Ruta y Método HTTP:'''<source lang="http">
GET /api/v1/forms/d3b07384-d113-4f4a-a62e-336712345678/history HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
</source>'''Descripción:''' Retorna el historial cronológico de auditoría con todas las modificaciones realizadas sobre el formulario.
 
'''Parámetros esperados:'''
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|uuid
|String
|Sí (Path)
|UUID del formulario.
|}
'''Ejemplo de Respuesta Exitosa (Código 200 OK):'''<source lang="json">
[
  {
    "auditoriaId": 801,
    "entidad": "formulario",
    "entidadId": "d3b07384-d113-4f4a-a62e-336712345678",
    "accion": "crear",
    "detalle": "Formulario creado con título 'Encuesta de Satisfacción en Visita'",
    "usuarioId": 5,
    "fecha": "2026-08-21T06:30:00Z"
  }
]
</source>'''Códigos de Error Posibles:'''
 
* '''401 Unauthorized''': Token inválido.
 
----
 
=== GET /api/v1/forms/stats ===
'''Ruta y Método HTTP:'''<source lang="http">
GET /api/v1/forms/stats HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
</source>'''Descripción:''' Calcula y devuelve los indicadores clave (KPIs) globales del Workspace para la empresa.
 
'''Parámetros esperados:'''
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|''Ninguno''
|N/A
|No
|No requiere parámetros.
|}
'''Ejemplo de Respuesta Exitosa (Código 200 OK):'''<source lang="json">
{
  "respuestasHoy": 142,
  "respuestasTotal": 12850,
  "formulariosActivos": 18
}
</source>'''Códigos de Error Posibles:'''
 
* '''401 Unauthorized''': No autenticado.
 
----
 
=== GET /api/v1/forms/{formId}/responses ===
'''Ruta y Método HTTP:'''<source lang="http">
GET /api/v1/forms/45/responses?startDate=2026-08-01T00:00:00Z&endDate=2026-08-21T23:59:59Z HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
</source>'''Descripción:''' Recupera el listado detallado de respuestas capturadas para un formulario específico dentro de un rango de fechas.
 
'''Parámetros esperados:'''
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|formId
|Integer
|Sí (Path)
|ID numérico interno del formulario.
|-
|startDate
|DateTime
|No (Query)
|Fecha inicial para filtrar respuestas.
|-
|endDate
|DateTime
|No (Query)
|Fecha final para filtrar respuestas.
|}
'''Ejemplo de Respuesta Exitosa (Código 200 OK):'''<source lang="json">
[
  {
    "respuestaId": 1024,
    "formId": 45,
    "fechaEnvio": "2026-08-21T07:05:00Z",
    "ipOrigen": "190.150.10.5",
    "payloadJson": "{\"idtercero\":1502,\"idsucursal\":1,\"respuestas\":[{\"pregunta_id\":\"q1\",\"valor\":\"Excelente\"}]}"
  }
]
</source>'''Códigos de Error Posibles:'''
 
* '''401 Unauthorized''': No autorizado.
* '''404 Not Found''': Formulario no encontrado.
 
----


=== GET /api/v1/forms/{formId}/responses/count ===
* '''Ruta y Método:''' <code>GET /api/v1/forms/public/{empresaid}/{uuid}</code>
'''Ruta y Método HTTP:'''<source lang="http">
GET /api/v1/forms/45/responses/count HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
</source>'''Descripción:''' Retorna el conteo total numérico de respuestas acumuladas por un formulario.


'''Parámetros esperados:'''
==== Parámetros ====
{| class="wikitable"
{| class="wikitable"
!Nombre del Parámetro
!Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|formId
|Integer
|Sí (Path)
|ID numérico interno del formulario.
|}
'''Ejemplo de Respuesta Exitosa (Código 200 OK):'''<source lang="json">
1024
</source>'''Códigos de Error Posibles:'''
 
* '''401 Unauthorized''': No autorizado.
 
----
 
=== GET /api/v1/forms/trash ===
'''Ruta y Método HTTP:'''<source lang="http">
GET /api/v1/forms/trash HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
</source>'''Descripción:''' Devuelve el listado de formularios que se encuentran actualmente desactivados en la papelera de reciclaje.
 
'''Parámetros esperados:'''
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|''Ninguno''
|N/A
|No
|No requiere parámetros.
|}
'''Ejemplo de Respuesta Exitosa (Código 200 OK):'''<source lang="json">
[
  {
    "formId": 32,
    "uuid": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
    "nombre": "Encuesta Prueba Papelera",
    "titulo": "Prueba de Concepto Antigua",
    "activo": false,
    "fechaEliminacion": "2026-08-15T10:00:00Z"
  }
]
</source>'''Códigos de Error Posibles:'''
 
* '''401 Unauthorized''': No autenticado.
 
----
 
=== PUT /api/v1/forms/{uuid}/restore ===
'''Ruta y Método HTTP:'''<source lang="http">
PUT /api/v1/forms/a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d/restore HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
</source>'''Descripción:''' Restaura un formulario de la papelera, reintegrándolo a la lista activa y reactivando la recepción de respuestas.
 
'''Parámetros esperados:'''
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|uuid
|String
|Sí (Path)
|UUID del formulario a restaurar.
|}
'''Ejemplo de Respuesta Exitosa (Código 204 No Content):'''<source lang="http">
HTTP/1.1 204 No Content
</source>'''Códigos de Error Posibles:'''
 
* '''401 Unauthorized''': No autenticado.
* '''404 Not Found''': El formulario no existe en la papelera.
 
----
 
=== GET /api/v1/forms/surveys/available ===
'''Ruta y Método HTTP:'''<source lang="http">
GET /api/v1/forms/surveys/available?contextos=Cliente,Proveedor&nittercero=900123456&usuarioid=10 HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
</source>'''Descripción:''' Evalúa la disponibilidad de encuestas para un tercero o usuario en tiempo real en el ERP durante una visita comercial, aplicando reglas anti-spam y ventanas de frecuencia (<code>repeatFrequency</code> / <code>repeatDays</code>).
 
'''Parámetros esperados:'''
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|contextos
|String
|No (Query)
|Lista de contextos separados por coma (ej. 'Cliente,Proveedor,Visita').
|-
|nittercero
|String
|No (Query)
|NIT o cédula del tercero visitado para evaluar ventanas de tiempo.
|-
|usuarioid
|Integer
|No (Query)
|ID del usuario o asesor que realiza la atención.
|}
'''Ejemplo de Respuesta Exitosa (Código 200 OK):'''<source lang="json">
[
  {
    "formId": 45,
    "uuid": "d3b07384-d113-4f4a-a62e-336712345678",
    "nombre": "Encuesta Visita Cliente",
    "titulo": "Encuesta de Satisfacción en Visita",
    "contexto": "Cliente",
    "repeatFrequency": "1w",
    "repeatDays": 7,
    "ultimaRespuestaFecha": "2026-08-10T14:20:00Z",
    "permiteResponder": true,
    "publicUrl": "/f/15/d3b07384-d113-4f4a-a62e-336712345678",
    "encuestaDeVisita": true
  }
]
</source>'''Códigos de Error Posibles:'''
 
* '''401 Unauthorized''': Sin autenticación válida de la empresa.
 
----
 
=== POST /api/v1/forms/terceros/verificar ===
'''Ruta y Método HTTP:'''<source lang="http">
POST /api/v1/forms/terceros/verificar?empresaid=15 HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
Content-Type: application/json
</source>'''Descripción:''' Recibe una lista de NITs o cédulas y valida cuáles de ellos tienen registros activos en la tabla <code>gdttercero</code> de la empresa.
 
'''Parámetros esperados:'''
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|empresaid
|Integer
|No (Query)
|ID de la empresa (si se omite, se usa el del token JWT).
|-
|''Body''
|Array
|Sí
|Arreglo de strings con los NITs a consultar.
|}
'''Ejemplo de Payload / Body:'''<source lang="json">
[
  "900123456",
  "800987654",
  "1098765432"
]
</source>'''Ejemplo de Respuesta Exitosa (Código 200 OK):'''<source lang="json">
{
  "900123456": 1502,
  "800987654": 1509
}
</source>'''Códigos de Error Posibles:'''
 
* '''401 Unauthorized''': Sin sesión activa.
 
----
 
=== GET /api/v1/forms/public/{empresaid}/{uuid} ===
'''Ruta y Método HTTP:'''<source lang="http">
GET /api/v1/forms/public/15/d3b07384-d113-4f4a-a62e-336712345678 HTTP/1.1
Host: api.serpi.com.co
</source>'''Descripción:''' Devuelve el esquema y diseño público de un formulario para renderizarse en el frontend. Endpoint de acceso público sin requerir token JWT.
 
'''Parámetros esperados:'''
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Tipo
!Obligatorio
!Obligatorio
Línea 939: Línea 209:
|Integer
|Integer
|Sí (Path)
|Sí (Path)
|ID de la empresa o 0 para resolver automáticamente por UUID.
|ID de la empresa o 0 para autocompletar.
|-
|-
|uuid
|uuid
|String
|String
|Sí (Path)
|Sí (Path)
|UUID público del formulario a consultar.
|UUID público del formulario.
|}
|}
'''Ejemplo de Respuesta Exitosa (Código 200 OK):'''<source lang="json">
{
  "titulo": "Encuesta de Satisfacción en Visita",
  "descripcion": "Por favor responda las siguientes preguntas",
  "esquemaJson": "{\"branding\":{\"theme\":\"light\"},\"components\":[{\"id\":\"q1\",\"type\":\"radio\",\"label\":\"¿Cómo fue la atención?\"}]}",
  "requiereSesionOnline": false,
  "sesionValida": false,
  "usuarioIdentificador": null,
  "defaultCompanyLogo": "https://cdn.serpi.com.co/logos/empresa15.png"
}
</source>'''Códigos de Error Posibles:'''


* '''404 Not Found''': Formulario inactivo o UUID inexistente.
=== POST /api/v1/forms/public/{empresaid}/{uuid}/responses ===
Endpoint público para registrar la respuesta de un encuestado. Garantiza inmutabilidad y orquesta el cobro de folio SaaS.


----
* '''Ruta y Método:''' <code>POST /api/v1/forms/public/{empresaid}/{uuid}/responses</code>


=== POST /api/v1/forms/public/{empresaid}/{uuid}/responses ===
==== Payload Esperado ====
'''Ruta y Método HTTP:'''<source lang="http">
<source lang="json">
POST /api/v1/forms/public/15/d3b07384-d113-4f4a-a62e-336712345678/responses HTTP/1.1
Host: api.serpi.com.co
Content-Type: application/json
</source>'''Descripción:''' Endpoint público para registrar la respuesta diligenciada por un encuestado. Garantiza inmutabilidad, captura la IP de origen y efectúa el cobro de folio SaaS.
 
'''Parámetros esperados:'''
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|empresaid
|Integer
|Sí (Path)
|ID de la empresa receptora.
|-
|uuid
|String
|Sí (Path)
|UUID del formulario a responder.
|-
|''Body''
|Object
|Sí
|Payload JSON con la estructura de respuestas en arreglo plano.
|}
'''Ejemplo de Payload / Body:'''<source lang="json">
{
  "respuestaJson": "{\"idtercero\":1502,\"idsucursal\":1,\"respuestas\":[{\"pregunta_id\":\"q1\",\"tipo\":\"radio\",\"valor\":\"Excelente\"}]}"
}
</source>'''Ejemplo de Respuesta Exitosa (Código 200 OK):'''<source lang="json">
{
{
   "respId": 2048,
   "respuestaJson": "{\"idtercero\":1502,\"idsucursal\":1,\"respuestas\":[{\"pregunta_id\":\"q1\",\"valor\":\"Excelente\"}]}"
  "billing_error": null
}
}
</source>'''Códigos de Error Posibles:'''
</source>
 
* '''400 Bad Request''': Formato JSON inválido o estructura no cumple con el esquema plano <code>respuestas</code>.
* '''404 Not Found''': Formulario inactivo o no encontrado.
 
----
 
== SaaS Billing ==


=== POST /api/v1/billing/process ===
=== POST /api/v1/billing/process ===
'''Ruta y Método HTTP:'''<source lang="http">
Orquestación interna SaaS para debitar folios transaccionales (Zero-Trust).
POST /api/v1/billing/process HTTP/1.1
Host: api.serpi.com.co
X-Secret-Key: Serpi-Dev-SaaS-Key-2026!
Content-Type: application/json
</source>'''Descripción:''' Endpoint de orquestación interna SaaS para debitar folios transaccionales (Zero-Trust). No utiliza JWT, sino el encabezado HTTP <code>X-Secret-Key</code>.
 
'''Parámetros esperados:'''
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|X-Secret-Key
|String
|Sí (Header)
|Clave secreta enviada en la cabecera HTTP.
|-
|''Body''
|Object
|Sí
|Datos del consumo de folio SaaS.
|}
'''Ejemplo de Payload / Body:'''<source lang="json">
{
  "empresaId": 15,
  "gdtProductoFolioId": 8,
  "referencia": "2048"
}
</source>'''Ejemplo de Respuesta Exitosa (Código 200 OK):'''<source lang="json">
{
  "message": "Cobro de folio registrado correctamente."
}
</source>'''Códigos de Error Posibles:'''


* '''400 Bad Request''': Configuración de pricing no encontrada o inactiva para la empresa.
* '''Autenticación:''' Utiliza el encabezado HTTP <code>X-Secret-Key</code> en lugar de JWT.
* '''401 Unauthorized''': Header <code>X-Secret-Key</code> ausente o incorrecto.
 
----
 
== Empresa ==


=== GET /api/v1/companies/logo ===
=== GET /api/v1/companies/logo ===
'''Ruta y Método HTTP:'''<source lang="http">
Obtiene el logotipo corporativo configurado en la base de datos maestra (retorna Base64 o URL). </tabber>
GET /api/v1/companies/logo HTTP/1.1
Host: api.serpi.com.co
Authorization: Bearer <TOKEN_JWT>
</source>'''Descripción:''' Obtiene el logotipo corporativo configurado en la base de datos maestra para la empresa del usuario autenticado (retornado en Base64 o URL).
 
'''Parámetros esperados:'''
{| class="wikitable"
!Nombre del Parámetro
!Tipo
!Obligatorio
!Descripción
|-
|''Ninguno''
|N/A
|No
|No requiere parámetros.
|}
'''Ejemplo de Respuesta Exitosa (Código 200 OK):'''<source lang="json">
{
  "logo": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
}
</source>'''Códigos de Error Posibles:'''
 
* '''401 Unauthorized''': Requiere sesión activa.

Revisión del 10:00 21 ago 2026

✨ SERPI Forms Core API (v1)

Descripción

El microservicio SERPI Forms proporciona almacenamiento, renderizado y análisis histórico de respuestas para formularios dinámicos. Opera bajo una arquitectura multi-tenant y se integra de forma nativa con el ERP SERPI, permitiendo a las empresas gestionar encuestas, auditorías y captura de datos en terreno.

Autorización

La API utiliza un esquema de seguridad basado en tokens JWT (Bearer Token). Para acceder a los endpoints protegidos, debes incluir el token en las cabeceras HTTP de tu petición:

Authorization: Bearer <TOKEN_JWT>

> Nota de Desarrollo: Si el bypass de desarrollo local está habilitado, se puede utilizar el encabezado `X-Empresa-Id: <ID>` en lugar del JWT.

Beneficio

  • Trazabilidad y Auditoría: Inmutabilidad de respuestas en el histórico y captura automática de la IP de origen (`ip_origen`).
  • Aislamiento de Datos (Multi-Tenant): Despliegue de bases de datos dedicadas por cliente para máxima seguridad.
  • Flexibilidad Estructural: Modelo híbrido Relacional/JSON que ofrece compatibilidad instantánea con motores de Inteligencia de Negocios (BI).

Tipos de peticiones

El API sigue los estándares RESTful utilizando los siguientes métodos HTTP:

  • GET: Recuperar información (ej. listar formularios, consultar carpetas o métricas).
  • POST: Crear nuevos recursos en el sistema o enviar respuestas públicas.
  • PUT: Actualizar recursos existentes, reubicar carpetas o cambiar estados (activo/inactivo).
  • DELETE: Ejecutar eliminaciones lógicas (soft-delete) o físicas de recursos protegidos.

¿Cómo funciona?

El ciclo de vida transaccional en SERPI Forms consta de los siguientes pasos:

  1. Configuración y Organización: Se crean Categorías (con reglas de roles) y Carpetas para organizar el entorno (Workspace).
  2. Diseño del Formulario: Se registra el esquema dinámico JSON que define las preguntas y lógicas del formulario.
  3. Distribución: Se generan URLs públicas o se habilitan para consultas en tiempo real durante visitas comerciales (aplicando reglas de frecuencia).
  4. Recolección: El encuestado diligencia los datos, impactando el endpoint público que registra la respuesta y orquesta el cobro SaaS (folios).
  5. Análisis: Se consultan los indicadores globales y el histórico de respuestas a través de los endpoints de gestión.

---

⚡ Referencia de Endpoints

<tabber> Categorías y Roles=

GET /api/v1/categories

Devuelve un listado completo de todas las categorías configuradas en el sistema para la empresa del usuario autenticado. Las categorías permiten organizar formularios y establecer políticas de acceso basado en roles (RBAC).

  • Ruta y Método: GET /api/v1/categories

Respuesta Exitosa (200 OK)

[
  {
    "categoriaId": 1,
    "nombre": "Encuestas de Satisfacción",
    "color": "#3B82F6",
    "roleIds": [101, 102]
  }
]
  • Errores posibles: 401 Unauthorized, 403 Forbidden

POST /api/v1/categories

Registra una nueva categoría en el sistema.

  • Ruta y Método: POST /api/v1/categories

Parámetros

Parámetro Tipo Obligatorio Descripción
Body Object Objeto JSON con nombre, color hexadecimal y roleIds.

Payload y Respuesta (201 Created)

{
  "nombre": "Control de Calidad",
  "color": "#F59E0B",
  "roleIds": [105, 108]
}

PUT y DELETE /api/v1/categories/{id}

  • PUT: Actualiza las propiedades de una categoría existente. Retorna 204 No Content.
  • DELETE: Elimina de forma física una categoría (falla si posee carpetas activas). Retorna 204 No Content.

GET /api/v1/categories/roles

Recupera todos los roles y perfiles configurados en la base de datos maestra del ERP (MvcSERPI) para la empresa actual.

  • Ruta y Método: GET /api/v1/categories/roles

|-| Carpetas y Workspace=

GET /api/v1/folders

Retorna la estructura jerárquica completa de carpetas, subcarpetas y formularios, filtrada automáticamente por los roles del usuario.

  • Ruta y Método: GET /api/v1/folders

Respuesta Exitosa (200 OK)

[
  {
    "id": "folder_10",
    "name": "Comercial 2026",
    "parentId": null,
    "categoriaId": 1,
    "color": "#3B82F6",
    "children": [],
    "forms": []
  }
]

POST /api/v1/folders

Crea una nueva carpeta en la raíz o como subcarpeta.

  • Ruta y Método: POST /api/v1/folders

Parámetros

Parámetro Tipo Obligatorio Descripción
Body Object Datos de la carpeta (name, parentId, categoriaId).

PUT y DELETE /api/v1/folders/{id}

  • PUT: Renombra o mueve una carpeta existente. Retorna 204 No Content.
  • DELETE: Borrado lógico en cascada de una carpeta y sus dependencias. Retorna 204 No Content.

GET /api/v1/folders/{id}/history

Obtiene la bitácora de auditoría histórica de eventos sobre la carpeta (creación, renombramiento, etc).

|-| Formularios Dinámicos=

POST /api/v1/forms

Crea un nuevo formulario dinámico asociando su esquema JSON y retornando un UUID no secuencial para la URL pública.

  • Ruta y Método: POST /api/v1/forms

Parámetros

Parámetro Tipo Obligatorio Descripción
Body Object Payload con nombre, título, descripción, carpetaId y esquemaJson.

Respuesta Exitosa (201 Created)

{
  "formId": 45,
  "uuid": "d3b07384-d113-4f4a-a62e-336712345678",
  "titulo": "Encuesta de Satisfacción en Visita",
  "urlPublica": "/f/15/d3b07384-d113-4f4a-a62e-336712345678"
}

Endpoints de Gestión de Formularios

  • PUT /api/v1/forms/{uuid}: Actualiza esquema JSON y detalles.
  • DELETE /api/v1/forms/{uuid}: Borrado lógico (Soft Delete) hacia la papelera.
  • PUT /api/v1/forms/{uuid}/toggle-status: Activa o desactiva el formulario.
  • PUT /api/v1/forms/{uuid}/move?carpetaId={id}: Reubica el formulario en otra carpeta.
  • GET /api/v1/forms/{uuid}/history: Auditoría cronológica de modificaciones.
  • PUT /api/v1/forms/{uuid}/restore: Restaura un formulario desde la papelera.

Endpoints de Respuestas y Métricas

  • GET /api/v1/forms/stats: Devuelve KPIs globales (respuestasHoy, respuestasTotal, formulariosActivos).
  • GET /api/v1/forms/{formId}/responses: Listado detallado de respuestas (soporta startDate y endDate).
  • GET /api/v1/forms/{formId}/responses/count: Conteo numérico total de respuestas.

Disponibilidad y Terceros

  • GET /api/v1/forms/surveys/available: Evalúa encuestas disponibles para un tercero, aplicando reglas anti-spam.
  • POST /api/v1/forms/terceros/verificar: Valida registros activos en gdttercero enviando un arreglo de NITs.

|-| Público, SaaS y Empresa=

GET /api/v1/forms/public/{empresaid}/{uuid}

Devuelve el esquema y diseño público de un formulario para renderizarse en el frontend. (No requiere JWT).

  • Ruta y Método: GET /api/v1/forms/public/{empresaid}/{uuid}

Parámetros

Parámetro Tipo Obligatorio Descripción
empresaid Integer Sí (Path) ID de la empresa o 0 para autocompletar.
uuid String Sí (Path) UUID público del formulario.

POST /api/v1/forms/public/{empresaid}/{uuid}/responses

Endpoint público para registrar la respuesta de un encuestado. Garantiza inmutabilidad y orquesta el cobro de folio SaaS.

  • Ruta y Método: POST /api/v1/forms/public/{empresaid}/{uuid}/responses

Payload Esperado

{
  "respuestaJson": "{\"idtercero\":1502,\"idsucursal\":1,\"respuestas\":[{\"pregunta_id\":\"q1\",\"valor\":\"Excelente\"}]}"
}

POST /api/v1/billing/process

Orquestación interna SaaS para debitar folios transaccionales (Zero-Trust).

  • Autenticación: Utiliza el encabezado HTTP X-Secret-Key en lugar de JWT.

Obtiene el logotipo corporativo configurado en la base de datos maestra (retorna Base64 o URL). </tabber>