API REST — Integración de suscripciones

Endpoints para que la web comercial de Help U consulte planes, valide empresas y confirme pagos de suscripción en Habitta.

Versión 1.0.1 · Actualizado Julio 2026

1. Introducción

Habitta expone una API REST para que la página web comercial (checkout de planes) sincronice pagos de suscripción con el panel multi-tenant. La pasarela de pago vive en la web; Habitta no aloja el formulario de cobro, solo recibe la confirmación del pago exitoso.

Alcance actual
  • Consulta de planes activos para mostrar precios en la web.
  • Consulta de temas visuales.
  • Alta de empresa + administrador sin pasar por demo.
  • Validación de empresa por NIT o correo antes del checkout.
  • Registro del pago, renovación de suscripción y activación opcional de la empresa.

Para operación del panel (empresas, demos, avisos) consulte el manual de SuperAdmin. Para usuarios de conjuntos, use el manual de usuario.

2. Autenticación

Todos los endpoints requieren un token compartido configurado en el servidor Habitta.

EncabezadoValor
Authorization Bearer {HABITTA_API_TOKEN} recomendado
X-Habitta-Token {HABITTA_API_TOKEN} (alternativa)

Respuestas de autenticación:

HTTPerrorCausa
401no_autorizadoToken ausente o incorrecto.
503api_no_configuradaHABITTA_API_TOKEN vacío en .env.

3. URL base y convenciones

  • Prefijo: todas las rutas están bajo /api.
  • Formato: JSON en peticiones (Content-Type: application/json) y respuestas.
  • Fechas: formato Y-m-d (ej. 2026-07-05).
  • Moneda: valores numéricos en COP sin separadores.

Ejemplo de URL base en producción (ajuste en config.php de esta carpeta):

https://habitta.su-dominio.com/api

4. Listar planes

GET /api/public/planes

Devuelve el catálogo activo para la web comercial. Use el query tipo para distinguir planes de la app y packs de asamblea.

Parámetros (query string)

ParámetroValoresDescripción
tipo plataforma · app · asamblea Opcional. Default: plataforma (alias app). asamblea trae packs 1/3/5.

Respuesta 200 (planes app)

{
  "ok": true,
  "tipo": "plataforma",
  "planes": [
    {
      "plan_id": 2,
      "codigo": "esencial",
      "nombre": "Esencial",
      "tipo": "plataforma",
      "dias_aviso": 7,
      "activo": true,
      "es_demo": false,
      "capacidades": ["Cartera", "Reservas", "PQRS"],
      "valor_unidad": 4500,
      "valor_unidad_fmt": "$4.500",
      "formula": "unidades × valor_unidad × meses × (1 − descuento_pct/100)",
      "tarifas": [
        {
          "rango_unidades_id": 1,
          "etiqueta": "Hasta 50 unidades",
          "unidades_desde": 1,
          "unidades_hasta": 50,
          "requiere_cotizacion": false,
          "precio_mensual": 4500,
          "precio_mensual_fmt": "$4.500",
          "precio_mensual_hasta": 225000,
          "precio_mensual_hasta_fmt": "$225.000"
        }
      ],
      "periodos": [
        {
          "periodo_facturacion_id": 1,
          "codigo": "mensual",
          "nombre": "Mensual",
          "meses": 1,
          "descuento_pct": 0
        }
      ]
    }
  ]
}

capacidades son nombres de submenú (legibles), no claves de permiso. No incluyen módulos de asamblea (Convocatorias / portal asamblea): esos se ofrecen aparte con ?tipo=asamblea. El precio de app usa valor_unidad del .env (VALOR_UNIDAD_ESENCIAL / VALOR_UNIDAD_INTELIGENTE; Demo usa Inteligente). Las tarifas conservan la lógica de rangos (1–50, 51–100, …; +700 = cotización); precio_mensual / precio_mensual_hasta son el total mensual de referencia en el piso y techo del rango. El cobro exacto se obtiene con /api/public/cotizar. Ver tabla en el manual SuperAdmin.

Respuesta 200 (packs asamblea)

{
  "ok": true,
  "tipo": "asamblea",
  "planes": [
    {
      "plan_id": 10,
      "codigo": "asamblea_1",
      "nombre": "1 asamblea",
      "tipo": "asamblea",
      "asambleas": 1,
      "capacidades": [],
      "tarifas": [ /* precio del pack por rango */ ],
      "periodos": []
    }
  ]
}
El pack asamblea es un servicio adicional: al confirmar el pago se crea un registro en empresa_servicios_asamblea y se activa empresas.asamblea sin reemplazar la suscripción del plan app. Detalle de precios: manual SuperAsamblea.

4.1 Cotizar plan

GET /api/public/cotizar

Calcula el precio del periodo según plan, unidades y periodo.

Parámetros

ParámetroTipoDescripción
planinteger o stringObligatorio. ID del plan o código (esencial, inteligente, demo, asamblea_1, …).
unidadesinteger (min 1)Obligatorio. Unidades administradas: definen el rango tarifario y, en planes app, multiplican el valor unitario.
periodointeger o stringOpcional. ID o código del periodo (mensual, trimestral, …).

Respuesta 200: { "ok": true, "cotizacion": { ... } }

4.2. Listar temas

GET /api/public/temas

Devuelve los temas visuales disponibles para registro o selección en la web comercial.

Respuesta 200

{
  "ok": true,
  "temas": {
    "default": {
      "id": 1,
      "show_name": "Predeterminado",
      "primary": "#1B4F8A",
      "primary_dark": "#143862",
      "primary_light": "#2563A8",
      "accent": "#3B9AE8",
      "accent_dark": "#2E8AD0",
      "surface": "#F4F8FC",
      "footer_bar": "#E8EEF5",
      "tag": "baDZr8M69O"
    },
    "red": {
      "id": 2,
      "show_name": "Rojo",
      "primary": "#991B1B",
      "primary_dark": "#7F1D1D",
      "primary_light": "#B91C1C",
      "accent": "#F87171",
      "accent_dark": "#EF4444",
      "surface": "#FEF2F2",
      "footer_bar": "#FEE2E2",
      "tag": "8XmnVjnR1L"
    }
  }
}

4.3. Listar ciudades

GET /api/public/ciudades

Devuelve las ciudades disponibles para seleccionar municipio en el formulario de alta.

Respuesta 200

{
  "ok": true,
  "ciudades": [
    { "ciudad_id": 1, "nombre": "Cundinamarca" }
  ]
}

4.4. Listar municipios

GET /api/public/municipios?ciudad_id=1

Devuelve los municipios de una ciudad. El municipio_id se usa en POST /public/empresas.

Parámetros (query string)

ParámetroTipoDescripción
ciudad_idintegerObligatorio. ID de ciudad.

Respuesta 200

{
  "ok": true,
  "ciudad_id": 1,
  "municipios": [
    {
      "municipio_id": 912,
      "ciudad_id": 1,
      "nombre": "Soacha",
      "codigo_dane": "25754"
    }
  ]
}

5. Consultar empresa

GET /api/public/empresas/consulta

Valida si existe una empresa cliente antes del pago. Indique al menos uno de los parámetros de consulta.

Parámetros (query string)

ParámetroTipoDescripción
nitstringNIT de la empresa sin dígito de verificación (ni guión).
emailstringCorreo registrado de la empresa.

Respuesta 200

{
  "ok": true,
  "existe": true,
  "activo": false,
  "empresa": {
    "empresa_id": 12,
    "nombre": "Conjunto Residencial Ejemplo",
    "nit": "900123456",
    "email": "admin@ejemplo.com",
    "activo": false,
    "asamblea": false,
    "plan_actual": "demo",
    "plan_nombre": "Demo",
    "plan_vence": "2026-07-01",
    "es_demo": true,
    "dias_restantes": 12,
    "estado_suscripcion": "vencido",
    "servicio_asamblea": null
  }
}

Si el NIT no existe: existe: false, activo: false, empresa: null (HTTP 200). Valores de estado_suscripcion: al_dia, proximo_vencer, vencido. También se exponen plan_nombre, es_demo y dias_restantes junto a plan_actual y plan_vence. Con pack contratado, servicio_asamblea incluye plan_codigo, asambleas_contratadas y fechas.

No se devuelve información de la empresa gestora (operador Habitta). Use este endpoint solo para clientes.

5.1. Alta comercial (sin demo)

POST /api/public/empresas

Crea una empresa nueva con su usuario administrador sin plan demo. La empresa queda activo: false hasta que el webhook de pago la active y asigne el plan. Úselo cuando el cliente compra desde la web sin pasar por solicitud de demo.

Cuerpo JSON

CampoObligatorioDescripción
nitNIT del conjunto sin dígito de verificación (ni guión).
nombreRazón social o nombre del conjunto.
direccionDirección.
telefonoTeléfono de contacto.
emailCorreo (también será el usuario admin).
municipio_idID de municipio en Habitta.
tema_idID de tema visual (GET /public/temas).

Ejemplo

{
  "nit": "900999888",
  "nombre": "Conjunto Los Alamos",
  "direccion": "Calle 10 # 20-30",
  "telefono": "3001234567",
  "email": "admin@losalamos.co",
  "municipio_id": 912,
  "tema_id": 1
}

Respuesta 201

{
  "ok": true,
  "empresa_id": 12,
  "nombre": "Conjunto Los Alamos",
  "nit": "900999888",
  "email": "admin@losalamos.co",
  "activo": false,
  "admin_email": "admin@losalamos.co",
  "tema_id": 1,
  "mensaje": "Empresa registrada. Confirme el pago para activarla y asignar el plan."
}
La clave inicial del administrador es el NIT (sin dígito de verificación ni guión). El correo de acceso se envía al activar la empresa vía POST /webhooks/suscripcion/pago.

6. Confirmar pago de suscripción

POST /api/webhooks/suscripcion/pago

Llame este endpoint después de que la pasarela confirme el cobro. Habitta registra el pago, renueva la suscripción y, por defecto, activa la empresa si estaba inactiva.

Cuerpo JSON

CampoObligatorioDescripción
referenciaID único de la transacción en la pasarela (idempotencia).
valorMonto pagado (numérico ≥ 0).
empresa_idUno de tres*ID interno de la empresa en Habitta.
nitUno de tres*NIT de la empresa sin dígito de verificación.
emailUno de tres*Correo de la empresa.
plan_idUno de dos**ID del plan en Habitta.
plan_codigoUno de dos**Código del plan app (demo, esencial, inteligente) o pack asamblea (asamblea_1, asamblea_3, asamblea_5).
unidadesUnidades contratadas (define el rango de tarifa).
periodo_codigoCondicionalObligatorio para plan app (mensual, trimestral, …). No aplica a packs asamblea.
fecha_pagoNoFecha del pago; por defecto hoy.
pasarelaNoNombre corto de la pasarela (ej. WOMPI, PAYU).
activar_empresaNotrue (default) activa la empresa si estaba inactiva.
reset_datos_demoNotrue borra datos operativos del demo (unidades, residentes, etc.) y conserva empresa + administrador. Solo aplica al pasar de plan demo a un plan de pago. Default: false (conservar datos).
observacionesNoTexto libre (máx. 500 caracteres).

* Debe enviar empresa_id, nit o email.
** Debe enviar plan_id o plan_codigo.

Vigencia al confirmar el pago (plan app)
  • Demo vigente → plan pago: inicia hoy y suma los días restantes del demo al vencimiento.
  • Demo vencido → plan pago: inicia hoy, sin días bonus.
  • Renovación pago → pago (vigente): el nuevo periodo empieza el día siguiente al vencimiento actual.
El campo valor debe coincidir con la tarifa publicada para el plan, rango y periodo (tolerancia ±1 COP); si no, Habitta responde 422.

Ejemplo de petición

POST /api/webhooks/suscripcion/pago
Authorization: Bearer su_token_secreto
Content-Type: application/json

{
  "referencia": "TX-98437261",
  "nit": "900123456",
  "plan_codigo": "esencial",
  "unidades": 50,
  "periodo_codigo": "mensual",
  "valor": 80000,
  "fecha_pago": "2026-07-05",
  "pasarela": "WOMPI",
  "activar_empresa": true,
  "reset_datos_demo": false
}

Respuesta 201 (pago nuevo — plan app)

{
  "ok": true,
  "idempotente": false,
  "empresa_id": 12,
  "empresa_nombre": "Conjunto Residencial Ejemplo",
  "empresa_activa": true,
  "pago_id": 45,
  "referencia": "WEB-WOMPI-TX-98437261",
  "valor": 80000,
  "fecha_pago": "2026-07-05",
  "suscripcion": {
    "empresa_suscripcion_id": 18,
    "plan_id": 2,
    "plan_codigo": "esencial",
    "plan_nombre": "Esencial",
    "fecha_inicio": "2026-07-05",
    "fecha_vencimiento": "2026-08-04",
    "activa": true,
    "estado": "al_dia"
  },
  "servicio_asamblea": null,
  "correo_activacion": {
    "enviado": true
  }
}

Si el pago es de un pack asamblea, suscripcion viene null y servicio_asamblea incluye el pack contratado (asamblea_1, etc.).

Respuesta 200 (reintento idempotente)

Si la misma referencia ya fue procesada, devuelve 200 con "idempotente": true y los mismos datos del pago original.

Respuesta 422 (validación)

{
  "ok": false,
  "error": "validacion",
  "mensaje": "Los datos enviados no son válidos.",
  "errores": {
    "empresa_id": ["No se encontró la empresa con los datos enviados."]
  }
}

7. Códigos de error

HTTPerrorDescripción
401no_autorizadoToken inválido.
404no_encontradaEmpresa no encontrada (consulta).
422validacionDatos incompletos o reglas de negocio (ej. empresa gestora).
500error_internoError inesperado; reintentar con la misma referencia.
503api_no_configuradaToken no configurado en el servidor.

8. Idempotencia y referencias

Habitta antepone un prefijo configurable a la referencia de la pasarela para evitar colisiones entre orígenes o reintentos. El formato es WEB[-PASARELA]-referencia. Variable de entorno: HABITTA_PAGO_PREFIJO (default WEB).

EntradaReferencia almacenada
referencia: "TX-001"WEB-TX-001
referencia: "TX-001", pasarela: "WOMPI"WEB-WOMPI-TX-001
Ante timeout o error 500, reenvíe la petición con la misma referencia. Habitta no duplicará el cobro ni la suscripción.

9. Flujo recomendado (web comercial)

Cliente nuevo que paga (sin demo)

  1. Mostrar planes y temas: GET /api/public/planes, GET /api/public/temas.
  2. Registrar empresa: POST /api/public/empresas → obtener empresa_id.
  3. Cobrar en la pasarela con el monto del plan.
  4. Confirmar: POST /api/webhooks/suscripcion/pago con empresa_id, plan y activar_empresa: true.
  5. Mostrar login; el admin usa el correo de la empresa y la clave = NIT (sin dígito de verificación).

Cliente existente / demo

  1. GET /api/public/empresas/consulta (NIT o correo).
  2. Checkout Help U «Ya soy cliente» con el NIT validado.
  3. Cobro Wompi → Help U recibe el evento en webhooks/wompi-events.php o consulta estado en registro-pago.php (polling local).
  4. POST /api/webhooks/suscripcion/pago a Habitta con referencia = UUID de la transacción Wompi, pasarela: "WOMPI" y datos del plan (opcional reset_datos_demo: true al salir de demo).

La reference del checkout Wompi suele ser tipo HELP-…; la referencia enviada a Habitta es el UUID de la transacción, no la referencia del checkout.

Las solicitudes de demo desde /registro crean empresas inactivas con plan demo que pueden pagar por este mismo webhook o ser activadas desde el panel (ver bandeja de demos).

10. Configuración en Habitta

Variables en el archivo .env del servidor Habitta:

VariableDescripción
HABITTA_API_TOKENToken secreto compartido con la web. Generar con php -r "echo bin2hex(random_bytes(32));"
HABITTA_PAGO_PREFIJOPrefijo de referencias externas (default WEB).

En el servidor Habitta, la integración usa el token anterior y las rutas bajo el prefijo /api. El código fuente de la API vive en el despliegue de Habitta, no en esta carpeta de documentación.