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 2024). Disponible si se consultó en LicitIA en los últimos 7 días. |
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, red_no_calculada | 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/900123456".
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 (si la red se calculó en LicitIA en los últimos 7 días). |
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), ChatGPT y clientes que solo piden una dirección
En Claude: Configuración → Conectores → Agregar conector personalizado. 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.