Files
cotizador/api/COTIZADOR_API_SKILL.md
urieljarethandClaude Opus 5 20f535d485 Retirar el servidor MCP y fijar todas las dependencias del API
MCP: se retira por completo (endpoint, paquete api/app/mcp/ y dependencia).
Tres razones, en orden de peso:

- Nadie lo usa.
- Llevaba roto desde antes de este trabajo. Con credencial valida devolvia 500:
  el handler construia un StreamableHTTPServerTransport nuevo por peticion, sin
  manejo de sesion. Lo que estaba expuesto a internet era la puerta abierta de un
  cuarto averiado.
- Su SDK sin fijar tumbo el API entero en produccion al saltar a 2.0.0.

Retirarlo es una mitigacion mas fuerte que autenticarlo, que fue lo que hizo el
commit anterior. Recuperable con `git show edb500f5:api/app/mcp/server.py`.
Se limpia tambien la ruta "/mcp" que el endpoint raiz seguia anunciando, y las
menciones a MCP del docstring y la descripcion de Swagger.

Dependencias: once de las doce eran rangos `>=` sin techo, o sea que cada
reconstruccion era una tirada de dados contra PyPI. `pydantic>=2.0` habria
aceptado pydantic 3 con la misma alegria con la que `mcp>=1.0.0` acepto 2.0.0.
Ahora todas van fijadas a la version exacta que corre sana en produccion,
capturada con pip freeze del contenedor healthy.

El lado Next.js ya era reproducible via package-lock.json; por eso el web nunca
se cayo durante el incidente y el api si.

Docs actualizados: AGENTS.md, README.md, api/COTIZADOR_API_SKILL.md y el spec,
que ademas registra en su seccion 0 las tres desviaciones de Fase 0 respecto a
lo disenado (el Despliegue B cancelado, la retirada del MCP y la deriva de
dependencia).

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-28 17:51:21 -06:00

12 KiB
Raw Permalink Blame History

Cotizador E3 — API Documentation for AI Skills

Overview

REST API for Consultoría E3's digital marketing quotation system. Allows AI agents to manage clients, browse service catalogs, create quotations, calculate financing, generate PDF/Excel documents, and manage the full sales pipeline.

Base URL: http://localhost:8000 Auth: API Key via X-API-Key header or Authorization: Bearer <key> Content-Type: application/json OpenAPI Spec: GET /openapi.json (no auth required)


Domain Context

Consultoría E3 is a digital marketing agency in Querétaro, México. Services are organized in 4 project phases:

  • Fase 0 — Auditoría / Acompañamiento: Initial assessments and ongoing consulting
  • Fase 1 — Setup e Infraestructura: One-time setup (websites, branding, CRM config)
  • Fase 2 — Publicidad y Manejo: Ongoing advertising and social media management
  • Fase 3 — Contenido y SEO: Content creation and search engine optimization

Two payment types:

  • unico: One-time payment
  • mensual: Monthly recurring payment

Currency: MXN (Mexican Pesos) or USD. IVA (tax) rate: 16%.


Authentication

API Key (for agents)

X-API-Key: your-api-key-here

or

Authorization: Bearer your-api-key-here

JWT (for human login)

POST /auth/login
Body: { "email": "[email protected]", "password": "secret" }
Response: { "user": { "id", "name", "email", "role" } }
Sets cookie: cotizador-session (httpOnly, 7 days)

Endpoints Reference

Health & Info

GET /health

Health check endpoint. No auth required.

  • Response: { "status": "ok", "timestamp": "2026-05-03T..." }

GET /api-info

API capabilities and version info.

  • Response: { "name": "Cotizador E3 API", "version": "1.0.0", "capabilities": [...] }

Clients (Clientes)

GET /clientes

List clients with optional search and pagination.

  • Query params: ?q=texto&page=1&limit=50
  • Response: { "data": [Cliente], "meta": { "total", "page", "limit", "pages" } }

POST /clientes

Create a new client.

  • Body:
{
  "nombre": "Juan Pérez",
  "empresa": "ACME Corp",
  "email": "[email protected]",
  "telefono": "4421234567"
}
  • Response (201): Full Cliente object with id

GET /clientes/{id}

Get client details including recent quotations.

  • Response: Cliente object + cotizaciones array

PUT /clientes/{id}

Update client information.

  • Body: Same as POST (all fields optional for update)

DELETE /clientes/{id}

Delete client. Returns 409 if client has quotations.

  • Response (200): { "ok": true }
  • Error (409): { "error": "Cliente tiene N cotizaciones asociadas" }

List all active services with optional filters.

  • Query params: ?fase=0&tipoPago=mensual&categoriaId=xxx&q=seo
  • Response: Array of ServicioCatalogo objects

Each service:

{
  "id": "cuid",
  "nombre": "Posicionamiento SEO",
  "descripcion": "...",
  "fase": 3,
  "tipoPago": "mensual",
  "precioBase": 2900,
  "tiempoEntrega": "7 - 14 dias",
  "entregablesDefault": ["Keyword research", "On-page optimization"],
  "categoriaId": "cuid",
  "variante": null,
  "activo": true,
  "orden": 0
}

Create a new service.

  • Body:
{
  "nombre": "Nuevo Servicio",
  "descripcion": "Descripción del servicio",
  "fase": 1,
  "tipoPago": "unico",
  "precioBase": 5000,
  "tiempoEntrega": "7 - 14 dias",
  "entregablesDefault": ["Entregable 1", "Entregable 2"],
  "categoriaId": "cuid",
  "variante": null,
  "orden": 0
}

GET /catalogo/{id}

Get service details with category info.

PUT /catalogo/{id}

Update service. Same body as POST.

DELETE /catalogo/{id}

Soft-delete if used in quotations, hard-delete otherwise.

  • Response: { "ok": true, "archived": true|false }

Categories (Categorías)

Available: SEO (#10b981), Marketing (#6366f1), Paid Media (#f59e0b), Desarrollo Web (#3b82f6), Automatizaciones (#8b5cf6), CRM (#ec4899), Desarrollo Personalizado (#14b8a6)

GET /categorias

List all categories ordered by orden.

POST /categorias

  • Body: { "nombre": "Nueva Cat", "descripcion": "...", "color": "#6b7280", "orden": 0 }

GET /categorias/{id}

Get category with its services.

PUT /categorias/{id}

  • Body: { "nombre", "descripcion", "color", "orden", "activo" }

DELETE /categorias/{id}

Returns 409 if category has associated services.


Quotations (Cotizaciones)

GET /cotizaciones

List quotations with filters.

  • Query params: ?estado=borrador&asesorId=xxx&clienteId=xxx&q=texto&desde=2026-01-01&hasta=2026-12-31&page=1&limit=50
  • Response: Array with full relations (cliente, asesor, servicios+catalogo, planBucefalo)

POST /cotizaciones

Create a complete quotation. Auto-creates client if not found.

  • Body:
{
  "numero": "UJ2605AG001",
  "fecha": "2026-05-03",
  "vigencia": "2026-05-24",
  "moneda": "MXN",
  "tipoCambio": "NA",
  "proyecto": "MKT Digital",
  "esquemaPago": "Pago Unico/Mensual",
  "incluirBonos": false,
  "incluirFinanciamiento": false,
  "observaciones": "",
  "asesorId": "cuid",
  "cliente": {
    "nombre": "Juan Pérez",
    "empresa": "ACME Corp",
    "email": "[email protected]",
    "telefono": "4421234567"
  },
  "servicios": [
    {
      "catalogoId": "cuid",
      "nombre": "SEO On-Page",
      "fase": 3,
      "tipoPago": "mensual",
      "precio": 2900,
      "tiempoEntrega": "7 - 14 dias",
      "entregables": ["Keyword research", "On-page SEO"]
    }
  ],
  "planBucefalo": {
    "nivel": "basico",
    "precio": 1000
  }
}

GET /cotizaciones/{id}

Get quotation with all relations.

PUT /cotizaciones/{id}

Update quotation. Replaces all services in a transaction.

  • Body: Same as POST without numero and asesorId. Optional estado.

DELETE /cotizaciones/{id}

Hard-delete with cascade.

PATCH /cotizaciones/{id}/precio

Update price of a single service.

  • Body: { "servicioId": "cuid", "precio": 7500 }

PATCH /cotizaciones/{id}/estado

Change quotation status.

  • Body: { "estado": "enviada" }borrador, enviada, aprobada, rechazada

POST /cotizaciones/{id}/duplicate

Duplicate quotation as new copy in borrador state.


Packages (Paquetes)

GET /paquetes

List active packages with nested phases and services.

POST /paquetes

  • Body:
{
  "nombre": "Paquete Básico",
  "descripcion": "...",
  "fases": [
    { "nombre": "Auditoría", "orden": 0 },
    { "nombre": "Setup", "orden": 1 }
  ]
}

GET /paquetes/{id}

Get package with full nested structure.

PUT /paquetes/{id}

  • Body: { "nombre", "descripcion", "activo" }

DELETE /paquetes/{id}

Hard-delete with cascade.

POST /paquetes/{id}/manage

Multi-action endpoint:

  • { "action": "addFase", "nombre": "Fase 3", "orden": 2 }
  • { "action": "updateFase", "faseId": "cuid", "nombre": "New Name", "orden": 1 }
  • { "action": "deleteFase", "faseId": "cuid" }
  • { "action": "addServicio", "servicioCatalogoId": "cuid", "fasePaqueteId": "cuid" }
  • { "action": "removeServicio", "servicioCatalogoId": "cuid", "fasePaqueteId": "cuid" }

Configuration (Configuración)

Allowed keys: color_primario, color_secundario, logo_base64, razon_social, rfc, domicilio_fiscal, cuenta_nacional, clabe_interbancaria, cuenta_internacional, cuenta_internacional_swift, hora_centinela, anualidad_hosting, iva, terminos_condiciones, no_incluye, notas_adicionales

GET /configuracion

  • Response: { "color_primario": "#2563eb", "razon_social": "...", ... }

PUT /configuracion

Bulk upsert. Only whitelisted keys processed.

  • Body: { "color_primario": "#ff0000", "razon_social": "Nuevo Nombre" }

Bonuses (Bonos)

Available: Centinela Web, Workshop Buyer Persona, Workshop Propuesta de Valor, Membresía Premium, Mes Gratis CRM, Script de Ventas

GET /bonos


Financing (Financiamiento)

Months Rate Commission Min Amount
3 7.7% 2.5% $300
6 10.7% 2.5% $600
9 13.7% 2.5% $900
12 16.7% 2.5% $1,200

GET /financiamiento/planes

POST /financiamiento/calcular

  • Body: { "monto": 50000, "meses": 6 }
  • Response: { "pagoMensual", "ivaMensual", "totalMensual", "comisionTotal", "granTotal" }

GET /financiamiento/simulacion/{cotizacion_id}

Auto-calculate financing for existing quotation.


Export

POST /export/pdf — PDF from draft data

GET /export/pdf/{id} — PDF from saved quotation

POST /export/excel — Excel from draft data

GET /export/excel/{id} — Excel from saved quotation

GET /export/catalogo — CSV of active services

GET /export/catalogo/plantilla — CSV import template


Import

Bulk import services from CSV. multipart/form-data with file field.

  • Response: { "creados": 5, "omitidos": 2, "errores": [...] }

Business Rules

Quotation Number

Format: UJ{YY}{MM}{AsesorInitials}{sequence} — e.g., UJ2605AG001

Quotation Validity

15 business days from issue (excludes Sat/Sun).

CRM Bucefalo Plans

basico=$1,000/mes, estandar=$3,500/mes, premium=$4,500/mes, empresarial=$7,500/mes

Client Deduplication

Matched by (nombre, empresa) pair.

Service Soft-Delete

If referenced by quotations → activo=false. Otherwise hard-delete.

Financing Formula

comisionTotal = monto × comision%
montoConComision = monto + comisionTotal
pagoMensual = montoConComision × (1 + tasa) / meses
ivaMensual = pagoMensual × 0.16
totalMensual = pagoMensual + ivaMensual
granTotal = totalMensual × meses

Common Responses

Success (paginated)

{
  "data": [...],
  "meta": { "total": 45, "page": 1, "limit": 50, "pages": 1 }
}

Error

{ "error": "Message", "detail": "Details", "code": "ERROR_CODE" }

HTTP Codes

200=OK, 201=Created, 204=No Content, 400=Bad Request, 401=Unauthorized, 404=Not Found, 409=Conflict, 500=Server Error


Agent Workflows

Create quotation

1. GET /catalogo?fase=0          → audit services
2. GET /catalogo?fase=1          → setup services
3. GET /catalogo?fase=2&tipoPago=mensual → ongoing services
4. POST /financiamiento/calcular → simulate payments
5. POST /cotizaciones            → create quotation
6. GET /export/pdf/{id}          → generate PDF

Review pipeline

1. GET /cotizaciones?estado=borrador  → pending
2. GET /cotizaciones?estado=enviada   → awaiting
3. GET /cotizaciones?estado=aprobada  → won

Negotiate price

1. GET /cotizaciones/{id}          → current state
2. PATCH /cotizaciones/{id}/precio → adjust price
3. GET /export/pdf/{id}            → regenerate PDF

MCP Integration — removed (2026-07-28)

The /mcp endpoint and the api/app/mcp/ package no longer exist. Agents should use the REST endpoints documented above, authenticating with X-API-Key or a Bearer JWT.

It was removed for three reasons: nobody was using it; its transport had been broken for some time (it constructed a StreamableHTTPServerTransport per request with no session handling, returning 500 even with valid credentials); and its unpinned SDK took the entire API down in production when mcp released 2.0.0 and dropped Server.list_tools().

To bring it back: git show edb500f5:api/app/mcp/server.py. Pin the SDK to the 1.x series and fix the transport before mounting it again.


Environment

DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=postgres
DB_NAME=cotizador_e3
API_KEY=your-secret-api-key
JWT_SECRET=your-jwt-secret

Run

pip install -r requirements.txt
uvicorn main:app --reload --host 0.0.0.0 --port 8000
# Swagger: http://localhost:8000/docs
# ReDoc: http://localhost:8000/redoc
# OpenAPI: http://localhost:8000/openapi.json