471 lines
12 KiB
Markdown
471 lines
12 KiB
Markdown
# 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:**
|
||
```json
|
||
{
|
||
"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" }`
|
||
|
||
---
|
||
|
||
### Service Catalog (Catálogo)
|
||
|
||
#### GET /catalogo
|
||
List all active services with optional filters.
|
||
- **Query params:** `?fase=0&tipoPago=mensual&categoriaId=xxx&q=seo`
|
||
- **Response:** Array of ServicioCatalogo objects
|
||
|
||
Each service:
|
||
```json
|
||
{
|
||
"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
|
||
}
|
||
```
|
||
|
||
#### POST /catalogo
|
||
Create a new service.
|
||
- **Body:**
|
||
```json
|
||
{
|
||
"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:**
|
||
```json
|
||
{
|
||
"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:**
|
||
```json
|
||
{
|
||
"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
|
||
|
||
#### POST /import/catalogo
|
||
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)
|
||
```json
|
||
{
|
||
"data": [...],
|
||
"meta": { "total": 45, "page": 1, "limit": 50, "pages": 1 }
|
||
}
|
||
```
|
||
|
||
### Error
|
||
```json
|
||
{ "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
|
||
|
||
MCP server at `/mcp` for OpenClaw, Claude, ChatGPT.
|
||
|
||
### Tools
|
||
| Tool | Description |
|
||
|------|-------------|
|
||
| `buscar_servicios` | Search catalog by phase, payment type, category, text |
|
||
| `crear_cotizacion` | Create complete quotation in one call |
|
||
| `obtener_cotizacion` | Get quotation details |
|
||
| `listar_cotizaciones` | List with filters |
|
||
| `cambiar_estado_cotizacion` | Change status |
|
||
| `actualizar_precio_servicio` | Adjust service price |
|
||
| `duplicar_cotizacion` | Clone as draft |
|
||
| `calcular_financiamiento` | Calculate payments |
|
||
| `generar_pdf_cotizacion` | Generate PDF |
|
||
| `obtener_configuracion` | Company config |
|
||
| `listar_bonos` | Available bonuses |
|
||
| `listar_planes_bucefalo` | CRM plans |
|
||
|
||
### Resources
|
||
| Resource | Description |
|
||
|----------|-------------|
|
||
| `cotizador://servicios` | Full catalog |
|
||
| `cotizador://categorias` | Categories |
|
||
| `cotizador://configuracion` | Company config |
|
||
|
||
---
|
||
|
||
## 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
|
||
|
||
```bash
|
||
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
|
||
```
|