La inteligencia de LicitIA en tus sistemas
Lleva a Power BI, Excel, tu CRM o tu propio software los procesos de tu radar, tus contratos ganados con sus adiciones, el mercado de tu sector y la ficha de cualquier empresa por NIT. Y recibe cada proceso nuevo en tiempo real por webhook firmado.
La API y los webhooks no usan inteligencia artificial: no consumen los créditos de IA de tu plan. Son datos y avisos; los créditos solo se gastan en la evaluación de elegibilidad, las propuestas, el análisis de riesgos y el asistente.
Inicio rápido
- En LicitIA entra a Herramientas → Integraciones y pulsa Crear llave. Cópiala: solo se muestra una vez.
- Haz tu primera llamada:
curl -H "Authorization: Bearer lic_TU_LLAVE" \
"https://bqjhmvnlvdpvbxvqtodh.supabase.co/functions/v1/api-v1/v1/cuenta"La respuesta trae tu plan, tus límites y las categorías de tu radar:
{
"data": {
"plan": "Corporativo",
"limites": { "llamadas_por_minuto": 120, "filas_por_pagina": 1000, "dias_de_procesos": 365, "anios_de_historial": 10 },
"llave": { "prefijo": "lic_Ab12C3", "alcances": ["lectura"], "empresa_idx": 1, "expira": null },
"radar": { "categorias": ["consultoría", "obra civil"] }
}
}Dirección base de todas las llamadas: https://bqjhmvnlvdpvbxvqtodh.supabase.co/functions/v1/api-v1/v1
Recursos
Todos son GET y responden { "data": …, "meta": … }. Los parámetros y campos de cada uno están en la referencia.
| Recurso | Qué entrega |
|---|---|
GET/procesos | Procesos publicados que coinciden con tu radar, del último año. Filtros: categoria, departamento, valor_min, desde. |
GET/adjudicaciones | Contratos ganados por tu empresa en SECOP I y II, sin duplicados, con valor inicial, adiciones, prórrogas, suspensiones y cesiones. |
GET/mercado?familia=8111 | Quién gana en una familia UNSPSC (por NIT; consorcios por su código de grupo), cuántos oferentes hay por proceso (mediana) y qué entidades compran. |
GET/proveedores/{nit} | Ficha de cualquier empresa: contratos por año, entidad y familia, descuento típico, adiciones y prórrogas. |
GET/proveedores/{nit}/consorcios | Consorcios y uniones temporales donde participa, con su porcentaje y las victorias de cada grupo. |
GET/proveedores/{nit}/red | Contra quién compite: rivales, quién gana a quién y quién oferta más barato (SECOP II desde 2023), con las ofertas de cada proceso. Se guarda 7 días; si no hay copia, se calcula en el momento (20 a 40 s). |
GET/cuenta | Tu plan, tus límites y la llave en uso. |
Autenticación
Envía la llave en la cabecera Authorization: Bearer lic_… (o X-API-Key: lic_…). Cada llave:
- queda atada a una empresa de tu grupo: su radar, su NIT y sus contratos;
- se guarda en LicitIA solo como huella (hash): si la pierdes, revócala y crea otra;
- puedes tener hasta 5 activas, por ejemplo una por sistema, para revocar una sin tocar las demás.
Solo Power BI «Web básico» admite la llave en la URL (?apikey=lic_…). Evítalo en todo lo demás: la URL queda guardada en historiales y registros.
Paginación y límites
Las listas se piden por páginas con limite y desplazamiento. Cuando hay más, meta.siguiente trae el enlace listo para la próxima página; cuando es null, terminaste.
| Plan | Llamadas por minuto | Filas por página | Historial |
|---|---|---|---|
| Agencia | 60 | 500 | Procesos: 1 año · Contratos y mercado: 10 años |
| Corporativo | 120 | 1.000 | Procesos: 1 año · Contratos y mercado: 10 años |
Cada respuesta trae RateLimit-Limit, RateLimit-Remaining y RateLimit-Reset (segundos). Si te pasas recibes 429 con Retry-After: espera esos segundos y reintenta.
Errores
Los errores llegan como application/problem+json (RFC 9457). Decide por code, que no cambia; el texto de detail sí puede cambiar. Si escribes a soporte, incluye el request_id.
{
"type": "https://licitia.com.co/api/errores#limite_excedido",
"title": "Demasiadas solicitudes",
"status": 429,
"detail": "Pasaste de 60 llamadas por minuto. Reintenta en 23 s.",
"code": "limite_excedido",
"request_id": "6ac16c2f-05ee-40ae-8839-8e5776776a1e"
}| HTTP | code | Qué hacer |
|---|---|---|
| 400 | parametro_invalido, familia_requerida, nit_invalido, categoria_fuera_del_radar | Corrige el parámetro que indica el error. |
| 401 | llave_ausente, llave_invalida, llave_revocada, llave_vencida | Revisa la cabecera o crea una llave nueva. |
| 403 | plan_sin_api, plan_vencido, empresa_fuera_de_alcance | La cuenta no tiene acceso: revisa el plan o los permisos. |
| 404 | ruta_no_existe, sin_contratos, sin_ofertas | No hay datos para eso. |
| 409 | empresa_sin_nit | Añade el NIT de la empresa en su perfil de LicitIA. |
| 429 | limite_excedido | Espera Retry-After segundos. |
| 502 | fuente_no_disponible | SECOP no respondió. Reintenta en unos minutos. |
Power BI y Excel
Plantilla lista
La forma más rápida: un informe de Power BI con tres páginas (tus contratos, los procesos de tu radar y el mercado de tu sector) que se llena con tu llave.
- Descarga LicitIA-PowerBI.pbit y ábrelo con Power BI Desktop.
- Te pide los parámetros: la familia UNSPSC (p. ej.
8111), el departamento (NACIONALo uno), los años del mercado y de tus contratos, y los días de procesos. Luego los cambias en Transformar datos → Editar parámetros. - Cuando pida credenciales elige API web y pega tu llave
lic_…. Power BI la guarda en sus credenciales, no en el archivo, así que puedes compartir el informe sin compartir la llave. - Publícalo en el servicio de Power BI y programa la actualización; ahí también eliges API web en las credenciales del conjunto de datos.
¿Prefieres armar tu propio informe o usar Excel? LicitIA-PowerQuery.pq trae las mismas consultas para pegarlas a mano, y el tema de colores de LicitIA se importa en Vista → Temas → Buscar temas.
Consulta a mano
Power BI y Excel usan el mismo lenguaje (Power Query). Esta consulta trae todas las páginas de /procesos y guarda la llave en las credenciales de Power BI, no en el texto de la consulta:
- Power BI: Obtener datos → Consulta en blanco (Excel: Datos → Obtener datos → De otras fuentes → Consulta en blanco).
- Abre el Editor avanzado y pega:
let
Base = "https://bqjhmvnlvdpvbxvqtodh.supabase.co/functions/v1/api-v1/v1",
Tamano = 500,
Pagina = (desp as number) =>
Json.Document(Web.Contents(Base, [
RelativePath = "procesos",
Query = [limite = Number.ToText(Tamano), desplazamiento = Number.ToText(desp)],
ApiKeyName = "apikey"
])),
Paginas = List.Generate(
() => [d = 0, r = Pagina(0)],
each List.Count([r][data]) > 0,
each [d = [d] + Tamano, r = Pagina([d] + Tamano)],
each [r][data]),
Filas = List.Combine(Paginas),
Tabla = Table.FromRecords(Filas, null, MissingField.UseNull)
in
Tabla- Cuando pida credenciales elige API web y pega tu llave.
- Para otros recursos cambia
RelativePath:"adjudicaciones","mercado"(confamiliaenQuery),"proveedores/" & nit(el NIT de la empresa, 9 dígitos sin dígito de verificación).
La consulta se actualiza sola en el servicio de Power BI con la programación de tu conjunto de datos.
Asistentes de IA (MCP)
Conecta tu asistente (Claude, ChatGPT, Copilot, Cursor u otro compatible con MCP) a LicitIA con tu misma llave. El asistente consulta tus procesos, tus contratos en SECOP, el mercado de tu sector y la ficha de cualquier empresa, y lo combina con los documentos que tienes en tu computador: propuestas anteriores, certificaciones, APU.
Tu biblioteca no sale de tu equipo. El servidor MCP de LicitIA solo entrega datos de LicitIA; no recibe, no lee ni guarda tus documentos. Y la IA corre en tu asistente, así que no consume créditos de LicitIA.
https://bqjhmvnlvdpvbxvqtodh.supabase.co/functions/v1/mcpHerramientas
| Herramienta | Qué hace |
|---|---|
buscar_procesos | Procesos de tu radar, con filtros de categoría, departamento, valor y fecha. |
mis_contratos | Tus contratos en SECOP I y II, con adiciones y prórrogas. |
mercado_sector | Quién gana en una familia UNSPSC, descuento típico y entidades que más contratan. |
ficha_empresa | Contratos de cualquier empresa por NIT. |
consorcios_empresa | Consorcios y uniones temporales de una empresa, con su %. |
red_competidores | Contra quién compite una empresa, con las ofertas de cada proceso. Si no está guardada se calcula en el momento (20 a 40 s). |
licitia_cuenta | Tu plan, límites y categorías del radar. |
Trae además dos conversaciones listas: ¿Me sirve este proceso? (compara un proceso con tu experiencia de SECOP y de tus documentos) y ¿A qué precio ofertar?
Claude Code, Cursor, VS Code y clientes que aceptan cabeceras (recomendado)
La llave va en una cabecera y no queda en la dirección. Claude Code:
claude mcp add --transport http licitia https://bqjhmvnlvdpvbxvqtodh.supabase.co/functions/v1/mcp --header "Authorization: Bearer lic_…"Cursor (~/.cursor/mcp.json) o VS Code (.vscode/mcp.json, con "servers" y "type": "http"):
{
"mcpServers": {
"licitia": {
"url": "https://bqjhmvnlvdpvbxvqtodh.supabase.co/functions/v1/mcp",
"headers": { "Authorization": "Bearer lic_…" }
}
}
}Claude (web y escritorio)
- Configuración → Conectores → Agregar conector personalizado, con la dirección del servidor. Si dice que no pudo verificarlo, pulsa Continuar de todas formas.
- Autenticación: Sin inicio de sesión.
- Encabezados de solicitud → Agregar encabezado: nombre
X-Api-Key, valor tu llavelic_…(sin «Bearer»). Claude reservaAuthorizationpara su propio inicio de sesión.
ChatGPT y clientes que solo piden una dirección
Pega la dirección con tu llave al final:
https://bqjhmvnlvdpvbxvqtodh.supabase.co/functions/v1/mcp?apikey=lic_…Funciona, pero la llave queda guardada dentro de la dirección. Usa una llave solo para el asistente, con un nombre que la identifique, y revócala en Integraciones si dejas de usarla.
Está en los planes Agencia y Corporativo, con los mismos límites por minuto de la API.
Webhooks
Configura en Herramientas → Integraciones una URL https y elige qué eventos recibir. Cada evento llega como un POST.
| Evento | Cuándo llega | Extra en datos |
|---|---|---|
proceso.nuevo | Se publica un proceso que coincide con tu radar. | — |
proceso.adenda | Sale una adenda en un proceso de tu kanban. | cambio.adendas_antes, adendas_ahora, ultima_adenda_fecha |
proceso.cierre_cambiado | Cambia la fecha de cierre de un proceso de tu kanban. | cambio.cierre_antes, cierre_ahora |
proceso.estado | Cambia el estado en SECOP de un proceso de tu kanban (evaluación, adjudicado, desierto, cancelado…). | cambio.estado_antes, estado_ahora |
proceso.adjudicado | Se adjudica un proceso de tu kanban. | cambio.proveedor, nit, valor |
competidor.gano | Uno de los 30 rivales más frecuentes de tu red de competidores gana un proceso. | competidor.nombre, nit, coincidieron; y cambio con la adjudicación |
«Tu kanban» son los procesos que tienes como tarjeta, sin archivar. «Tu red» es la que calculaste en Mi Panel → Mis Adjudicaciones. Ejemplo de proceso.nuevo:
{
"id": "0b8e5c1e-6f61-4c3e-9a77-3b6e3c2b9f10",
"tipo": "proceso.nuevo",
"creado": "2026-10-30T14:20:22.009Z",
"version": "2026-10-30",
"datos": {
"codigo_proceso": "CO1.REQ.10598757",
"objeto": "Interventoría técnica, administrativa y financiera…",
"entidad": "GOBERNACION DEL DEPARTAMENTO DEL CESAR",
"departamento": "Cesar", "municipio": "Valledupar",
"valor": 3100000000, "modalidad": "Concurso de méritos abierto",
"tipo_contrato": "Interventoría", "categorias": ["consultoría"],
"fecha_publicacion": "2026-10-30", "fecha_cierre": "2026-11-14",
"fuente": "SECOP II", "link": "https://community.secop.gov.co/…"
}
}Cabeceras
LicitIA-Evento:proceso.nuevooprueba.LicitIA-Entrega: id único del envío; si te llega dos veces, descarta el repetido.LicitIA-Firma:t=<unix>,v1=<firma>.
Verificar la firma
Calcula HMAC-SHA256 con tu secreto (whsec_…) sobre <t>.<cuerpo crudo>, compáralo con v1 y rechaza si t tiene más de 5 minutos. Usa el cuerpo tal como llegó, antes de convertirlo a JSON.
const crypto = require("crypto");
app.post("/licitia", express.raw({ type: "application/json" }), (req, res) => {
const firma = req.get("LicitIA-Firma") || "";
const t = Number((firma.match(/t=(\d+)/) || [])[1]);
const v1 = (firma.match(/v1=([0-9a-f]+)/) || [])[1] || "";
const esperada = crypto.createHmac("sha256", process.env.LICITIA_SECRETO)
.update(`${t}.${req.body.toString("utf8")}`).digest("hex");
const vigente = Math.abs(Date.now() / 1000 - t) <= 300;
if (!vigente || v1.length !== esperada.length ||
!crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(esperada))) {
return res.sendStatus(401);
}
const evento = JSON.parse(req.body);
// … procesa evento.datos
res.sendStatus(200);
});import hmac, hashlib, os, re, time
from flask import request, abort
@app.post("/licitia")
def licitia():
firma = request.headers.get("LicitIA-Firma", "")
t = int((re.search(r"t=(\d+)", firma) or [0, 0])[1])
v1 = (re.search(r"v1=([0-9a-f]+)", firma) or [0, ""])[1]
cuerpo = request.get_data(as_text=True)
esperada = hmac.new(os.environ["LICITIA_SECRETO"].encode(),
f"{t}.{cuerpo}".encode(), hashlib.sha256).hexdigest()
if abs(time.time() - t) > 300 or not hmac.compare_digest(v1, esperada):
abort(401)
evento = request.get_json()
# … procesa evento["datos"]
return "", 200<?php
$cuerpo = file_get_contents('php://input');
$firma = $_SERVER['HTTP_LICITIA_FIRMA'] ?? '';
preg_match('/t=(\d+)/', $firma, $mt);
preg_match('/v1=([0-9a-f]+)/', $firma, $mv);
$t = (int)($mt[1] ?? 0);
$esperada = hash_hmac('sha256', $t . '.' . $cuerpo, getenv('LICITIA_SECRETO'));
if (abs(time() - $t) > 300 || !hash_equals($esperada, $mv[1] ?? '')) {
http_response_code(401); exit;
}
$evento = json_decode($cuerpo, true);
// … procesa $evento['datos']
http_response_code(200);Entregas y reintentos
- Responde
2xxen menos de 10 segundos; procesa lo pesado después. - Ante un error de red,
429o5xxreintentamos dos veces (a 1 y 4 segundos). Un4xxno se reintenta. - Tras 20 envíos fallidos seguidos el webhook se pausa; se reactiva al guardarlo de nuevo.
- En Integraciones ves los últimos envíos y el código con que respondió tu servidor, y puedes mandar un evento de
prueba.
Zapier y Make
- Zapier: crea un Zap con el disparador Webhooks by Zapier → Catch Hook, copia su URL en Integraciones y pulsa Enviar prueba para que Zapier vea los campos.
- Make: agrega el módulo Webhooks → Custom webhook, copia la URL y envía la prueba para que Make determine la estructura.
- Ideas: cada proceso nuevo como tarjeta en Trello o Asana, fila en Google Sheets o mensaje en Teams o Slack.
Zapier y Make no verifican la firma por sí mismos. Si el flujo hace algo sensible, verifícala con un paso de código antes de seguir.
Datos y licencia
- Fuente: Agencia Nacional de Contratación Pública – Colombia Compra Eficiente (SECOP I y II, datos.gov.co), bajo licencia CC BY-SA 4.0. Si publicas datos obtenidos por la API, cita la fuente.
- De personas naturales solo se entrega el nombre, nunca el documento. Quien pidió que se suprima su nombre aparece como «Persona natural». La API no consulta cédulas.
- Son registros públicos de SECOP: no son una evaluación de las empresas. Una corrección se pide ante la entidad que publicó el dato.
- Versionado:
/v1no tendrá cambios que rompan tus integraciones. Lo nuevo se agrega como campos o recursos adicionales; un cambio incompatible saldría como/v2, avisado con anticipación.
¿Dudas o algo no funciona? Escribe a info@licitia.com.co con el request_id de la respuesta.