F05 — Data & Contracts
20 --- API Design, Contracts & Versioning
Sección titulada «20 --- API Design, Contracts & Versioning»AI-First Engineering Framework --- Baseline v6.5
Sección titulada «AI-First Engineering Framework --- Baseline v6.5»Version: 1.0.0
Estado: Activo
Fecha: Marzo 2026
Autor: Engineering Team
Proposito
Sección titulada «Proposito»Definir los estandares para disenar, documentar, versionar y mantener APIs en proyectos AI-Driven. Cubre REST APIs, API Contracts (OpenAPI), versionado, paginacion, error handling y patrones especificos para endpoints que integran IA.
“Una API bien disenada es la interfaz entre el dominio de negocio y cualquier consumidor --- humano, frontend o agente IA.”
1. Principios de API Design
Sección titulada «1. Principios de API Design»principles: - name: "Contract-First" description: "El contrato OpenAPI se escribe ANTES del codigo" benefit: "Frontend y backend pueden trabajar en paralelo"
- name: "RESTful by Default" description: "Seguir constraints REST (stateless, uniform interface, HATEOAS)" exception: "GraphQL para frontends con queries complejas y variables"
- name: "Consistent & Predictable" description: "Misma estructura en todos los endpoints" benefit: "Reducir carga cognitiva para consumidores (humanos y agentes)"
- name: "Secure by Design" description: "Auth, rate limiting, input validation en todo endpoint" reference: "Doc 08 - Auth, Doc 11 - Compliance"
- name: "AI-Consumable" description: "Endpoints que un agente IA pueda descubrir y usar via MCP" reference: "Doc 03 - MCP Servers"
- name: "Observable" description: "Toda llamada genera traces, metricas y logs" reference: "Doc 09 - Observabilidad"2. URL Structure & Naming Conventions
Sección titulada «2. URL Structure & Naming Conventions»2.1 Base URL Pattern
Sección titulada «2.1 Base URL Pattern»https://api.{domain}.{tld}/v{major}/{resource}
Ejemplos: https://api.myapp.co/v1/customers https://api.myapp.co/v1/orders/{order_id}/items https://api.myapp.co/v1/ai/chat # Endpoints IA https://api.myapp.co/v1/ai/analyze # Endpoints IA2.2 Naming Rules
Sección titulada «2.2 Naming Rules»naming_conventions: resources: - "Sustantivos en plural: /customers, /orders, /products" - "Lowercase con hyphens: /tax-rules, /payment-methods" - "Maximo 3 niveles de anidamiento: /orders/{id}/items/{item_id}" - "Evitar verbos en URLs (usar HTTP methods)"
query_parameters: - "snake_case: ?page_size=20&sort_by=created_at" - "Filtros con prefijo: ?filter_status=active&filter_country=CO" - "Busqueda: ?search=texto libre" - "Campos especificos: ?fields=id,name,email"
request_body: - "camelCase en JSON (JavaScript convention)" - "Alternativa: snake_case si el backend es Python-first" - "IMPORTANTE: ser consistente en TODO el API"
special_endpoints: - "POST /v1/ai/chat → Conversaciones con agentes" - "POST /v1/ai/analyze → Analisis AI (DOFA, clasificacion, etc.)" - "GET /v1/ai/suggestions → Sugerencias proactivas" - "POST /v1/search → Busqueda semantica (RAG)"3. Standard Response Format
Sección titulada «3. Standard Response Format»3.1 Success Response
Sección titulada «3.1 Success Response»{ "data": { "id": "550e8400-e29b-41d4-a716-446655440000", "type": "customer", "attributes": { "name": "Empresa ABC", "email": "contacto@empresa.co", "country": "CO", "createdAt": "2026-03-10T14:30:00Z" } }, "meta": { "requestId": "req_abc123", "timestamp": "2026-03-10T14:30:01Z", "version": "v1" }}3.2 Collection Response (Paginated)
Sección titulada «3.2 Collection Response (Paginated)»{ "data": [ { "id": "...", "type": "customer", "attributes": { "..." } }, { "id": "...", "type": "customer", "attributes": { "..." } } ], "meta": { "requestId": "req_abc456", "timestamp": "2026-03-10T14:30:01Z", "version": "v1" }, "pagination": { "page": 1, "pageSize": 20, "totalItems": 143, "totalPages": 8, "hasNext": true, "hasPrev": false }}3.3 AI-Enhanced Response
Sección titulada «3.3 AI-Enhanced Response»{ "data": { "id": "analysis_789", "type": "ai_analysis", "attributes": { "result": "...", "confidence": 0.92, "model": "claude-sonnet-4-5", "sources": [ { "chunkId": "chunk_abc", "documentTitle": "Politica de credito v3", "relevanceScore": 0.95 } ] } }, "meta": { "requestId": "req_xyz", "timestamp": "2026-03-10T14:30:02Z", "version": "v1", "ai": { "modelUsed": "claude-sonnet-4-5", "tokensUsed": 1250, "latencyMs": 1800, "cached": false, "disclaimer": "Respuesta generada por IA. Verifique con fuentes oficiales." } }}3.4 Error Response
Sección titulada «3.4 Error Response»{ "error": { "code": "VALIDATION_ERROR", "status": 422, "message": "Los datos enviados no son validos", "details": [ { "field": "email", "rule": "format", "message": "Formato de email invalido" }, { "field": "country", "rule": "enum", "message": "Pais debe ser un codigo ISO 3166-1 alpha-2 valido" } ], "requestId": "req_err123", "timestamp": "2026-03-10T14:30:03Z", "documentation": "https://docs.myapp.co/errors/VALIDATION_ERROR" }}3.5 Standard Error Codes
Sección titulada «3.5 Standard Error Codes»error_codes: # 4xx Client Errors VALIDATION_ERROR: { status: 422, description: "Input validation failed" } NOT_FOUND: { status: 404, description: "Resource not found" } UNAUTHORIZED: { status: 401, description: "Missing or invalid auth token" } FORBIDDEN: { status: 403, description: "Insufficient permissions" } CONFLICT: { status: 409, description: "Resource state conflict (optimistic lock)" } RATE_LIMITED: { status: 429, description: "Too many requests" } TENANT_MISMATCH: { status: 403, description: "Cross-tenant access attempted" }
# 5xx Server Errors INTERNAL_ERROR: { status: 500, description: "Unexpected server error" } SERVICE_UNAVAILABLE: { status: 503, description: "Dependency unavailable" }
# AI-specific errors AI_TIMEOUT: { status: 504, description: "LLM response timeout" } AI_RATE_LIMITED: { status: 429, description: "LLM rate limit reached" } AI_CONTENT_FILTERED: { status: 422, description: "Content filtered by guardrails" } AI_LOW_CONFIDENCE: { status: 200, description: "Response returned but low confidence" } AI_BUDGET_EXCEEDED: { status: 429, description: "Daily AI budget exceeded" }4. API Implementation Pattern
Sección titulada «4. API Implementation Pattern»4.1 Endpoint Template (ejemplo Python/FastAPI)
Sección titulada «4.1 Endpoint Template (ejemplo Python/FastAPI)»Nota: Este ejemplo usa Python/FastAPI. Adaptar al stack elegido en
project-config.yaml. Los patrones (paginacion, error handling, health check) son universales.
from fastapi import APIRouter, Depends, Query, HTTPException, Requestfrom uuid import UUIDfrom pydantic import BaseModel, Fieldfrom datetime import datetime
router = APIRouter(prefix="/v1/customers", tags=["Customers"])
# --- Request/Response Models ---
class CustomerCreate(BaseModel): name: str = Field(min_length=1, max_length=200) email: str = Field(pattern=r"^[\w.-]+@[\w.-]+\.\w+$") country: str = Field(min_length=2, max_length=2) # ISO 3166-1 tax_id: str | None = None metadata: dict = {}
class CustomerResponse(BaseModel): id: UUID type: str = "customer" attributes: dict
class PaginatedResponse(BaseModel): data: list meta: dict pagination: dict
# --- Endpoints ---
@router.get("/", response_model=PaginatedResponse)async def list_customers( request: Request, page: int = Query(1, ge=1), page_size: int = Query(20, ge=1, le=100), sort_by: str = Query("created_at"), sort_dir: str = Query("desc", pattern="^(asc|desc)$"), filter_status: str | None = Query(None), filter_country: str | None = Query(None), search: str | None = Query(None), tenant_id: UUID = Depends(get_current_tenant), # From JWT): """List customers with pagination, filtering and search."""
filters = {} if filter_status: filters["status"] = filter_status if filter_country: filters["country"] = filter_country
items, total = await customer_repo.list( tenant_id=tenant_id, filters=filters, search=search, page=page, page_size=page_size, order_by=sort_by, order_dir=sort_dir )
return PaginatedResponse( data=[_format_customer(c) for c in items], meta={ "requestId": request.state.request_id, "timestamp": datetime.utcnow().isoformat(), "version": "v1" }, pagination={ "page": page, "pageSize": page_size, "totalItems": total, "totalPages": (total + page_size - 1) // page_size, "hasNext": page * page_size < total, "hasPrev": page > 1 } )
@router.post("/", status_code=201)async def create_customer( request: Request, body: CustomerCreate, tenant_id: UUID = Depends(get_current_tenant), user_id: UUID = Depends(get_current_user),): """Create a new customer."""
customer = await customer_repo.save( Customer( tenant_id=tenant_id, created_by=user_id, **body.model_dump() ) )
return { "data": _format_customer(customer), "meta": { "requestId": request.state.request_id, "timestamp": datetime.utcnow().isoformat(), "version": "v1" } }
@router.get("/{customer_id}")async def get_customer( customer_id: UUID, tenant_id: UUID = Depends(get_current_tenant),): """Get a single customer by ID.""" customer = await customer_repo.get_by_id(customer_id, tenant_id) if not customer: raise HTTPException(status_code=404, detail={ "code": "NOT_FOUND", "message": f"Customer {customer_id} not found" }) return {"data": _format_customer(customer)}4.2 AI Endpoint Pattern
Sección titulada «4.2 AI Endpoint Pattern»from fastapi import APIRouterfrom fastapi.responses import StreamingResponse
ai_router = APIRouter(prefix="/v1/ai", tags=["AI"])
@ai_router.post("/chat")async def chat( request: Request, body: ChatRequest, tenant_id: UUID = Depends(get_current_tenant), user_id: UUID = Depends(get_current_user),): """ Chat endpoint con agente IA. Soporta streaming (SSE) y non-streaming. """
# 1. Check budget (Ref Doc 18 - FinOps) budget_ok = await cost_guard.check_budget(tenant_id) if not budget_ok: raise HTTPException(status_code=429, detail={ "code": "AI_BUDGET_EXCEEDED", "message": "Presupuesto diario de IA agotado" })
# 2. Input guard (Ref Doc 04 - Guardrails) sanitized = await input_guard.check(body.message)
# 3. Check semantic cache (Ref Doc 18) cached = await semantic_cache.get( query=sanitized.text, tenant_id=tenant_id ) if cached: return _format_ai_response(cached, from_cache=True)
# 4. Execute agent if body.stream: return StreamingResponse( _stream_agent_response(sanitized, tenant_id, user_id), media_type="text/event-stream" )
result = await agent.run( message=sanitized.text, session_id=body.session_id, tenant_id=tenant_id, user_id=user_id )
# 5. Cache response await semantic_cache.set( query=sanitized.text, response=result, tenant_id=tenant_id )
# 6. Return with AI metadata return _format_ai_response(result, from_cache=False)
@ai_router.post("/analyze")async def analyze( request: Request, body: AnalysisRequest, tenant_id: UUID = Depends(get_current_tenant),): """ Endpoint generico de analisis IA. Tipos: dofa, classification, summary, extraction, etc. """
analysis_type = body.analysis_type # dofa, classify, summarize, extract
result = await analysis_agent.run( analysis_type=analysis_type, data=body.data, parameters=body.parameters, tenant_id=tenant_id )
return { "data": { "id": result.id, "type": "ai_analysis", "attributes": { "analysisType": analysis_type, "result": result.output, "confidence": result.confidence, "sources": result.sources } }, "meta": { "requestId": request.state.request_id, "ai": { "modelUsed": result.model, "tokensUsed": result.tokens, "latencyMs": result.latency_ms, "disclaimer": "Analisis generado por IA. Requiere validacion humana." } } }5. API Versioning Strategy
Sección titulada «5. API Versioning Strategy»5.1 Versionado en URL (Recomendado)
Sección titulada «5.1 Versionado en URL (Recomendado)»versioning: strategy: "url_path" # /v1/resource, /v2/resource
rules: major_version: # v1 → v2 trigger: "Breaking changes (remove field, rename endpoint, change response format)" policy: "Mantener version anterior activa minimo 6 meses con deprecation headers"
minor_version: # No cambia URL trigger: "New fields (additive), new endpoints" policy: "Backward compatible, no requiere nueva version"
deprecation: header: "Deprecation: true" sunset_header: "Sunset: Sat, 01 Sep 2026 00:00:00 GMT" notice_period: "6 meses minimo" documentation: "Migration guide obligatoria"
# Headers informativos en toda respuesta response_headers: X-API-Version: "v1" X-Request-Id: "${REQUEST_ID}" X-RateLimit-Limit: "1000" X-RateLimit-Remaining: "995" X-RateLimit-Reset: "1710086400"5.2 Breaking vs Non-Breaking Changes
Sección titulada «5.2 Breaking vs Non-Breaking Changes»breaking_changes: # Requieren nueva version mayor - "Eliminar un campo del response" - "Cambiar el tipo de un campo (string → number)" - "Renombrar un endpoint" - "Cambiar comportamiento de un endpoint existente" - "Hacer obligatorio un campo que era opcional" - "Cambiar formato de autenticacion"
non_breaking_changes: # No requieren nueva version - "Agregar un campo nuevo al response" - "Agregar un endpoint nuevo" - "Agregar un query parameter opcional" - "Agregar un nuevo error code" - "Mejorar mensajes de error" - "Optimizar performance"6. Rate Limiting & Throttling
Sección titulada «6. Rate Limiting & Throttling»from dataclasses import dataclass
@dataclassclass RateLimitConfig: """Configuracion de rate limiting por plan."""
plans = { "free": { "requests_per_minute": 30, "requests_per_day": 1_000, "ai_requests_per_day": 50, "max_upload_mb": 5, "concurrent_requests": 5 }, "starter": { "requests_per_minute": 100, "requests_per_day": 10_000, "ai_requests_per_day": 500, "max_upload_mb": 25, "concurrent_requests": 10 }, "pro": { "requests_per_minute": 500, "requests_per_day": 100_000, "ai_requests_per_day": 5_000, "max_upload_mb": 100, "concurrent_requests": 50 }, "enterprise": { "requests_per_minute": 2_000, "requests_per_day": 1_000_000, "ai_requests_per_day": 50_000, "max_upload_mb": 500, "concurrent_requests": 200 } }7. API Security Checklist
Sección titulada «7. API Security Checklist»api_security: authentication: - "JWT Bearer token en Authorization header" - "Token expiry: 15 min access, 7 days refresh (Ref Doc 08)" - "API Keys para integraciones server-to-server" - "CORS configurado (solo origenes permitidos)"
authorization: - "RBAC (Role-Based Access Control)" - "Tenant isolation en TODA query (Ref Doc 08 - RLS)" - "Permisos granulares por endpoint y operacion" - "Agentes IA con permisos minimos (Ref Doc 03)"
input_validation: - "Pydantic/Zod schemas para todo request body" - "Query parameters tipados y con limites" - "File uploads: tipo MIME, tamano, antivirus" - "SQL injection protection (parameterized queries)" - "Prompt injection detection (Ref Doc 04 - Guardrails)"
output: - "No exponer stack traces en produccion" - "No exponer IDs internos de infraestructura" - "PII: solo si es necesario y con consentimiento" - "AI responses: incluir disclaimer obligatorio"
infrastructure: - "HTTPS obligatorio (TLS 1.3)" - "Rate limiting por tenant y por plan" - "Request size limit (default 10MB)" - "Timeout global (30s default, 120s para AI endpoints)" - "Health check endpoint: GET /health"8. OpenAPI Specification Template
Sección titulada «8. OpenAPI Specification Template»# openapi.yaml - Template base para todo proyectoopenapi: "3.1.0"info: title: "${PROJECT_NAME} API" version: "1.0.0" description: "API for ${PROJECT_DESCRIPTION}" contact: email: "${CONTACT_EMAIL}"
servers: - url: "https://api.${DOMAIN}/v1" description: "Production" - url: "https://api.staging.${DOMAIN}/v1" description: "Staging" - url: "http://localhost:8000/v1" description: "Development"
security: - bearerAuth: []
components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT
schemas: # Schemas reutilizables PaginationMeta: type: object properties: page: { type: integer } pageSize: { type: integer } totalItems: { type: integer } totalPages: { type: integer } hasNext: { type: boolean } hasPrev: { type: boolean }
Error: type: object properties: error: type: object properties: code: { type: string } status: { type: integer } message: { type: string } details: { type: array, items: { type: object } } requestId: { type: string } timestamp: { type: string, format: date-time }
AIMeta: type: object properties: modelUsed: { type: string } tokensUsed: { type: integer } latencyMs: { type: integer } cached: { type: boolean } disclaimer: { type: string }
responses: NotFound: description: "Resource not found" content: application/json: schema: { $ref: "#/components/schemas/Error" } Unauthorized: description: "Missing or invalid authentication" content: application/json: schema: { $ref: "#/components/schemas/Error" } RateLimited: description: "Rate limit exceeded" content: application/json: schema: { $ref: "#/components/schemas/Error" }
# Paths se definen por modulo/bounded contextpaths: /health: get: summary: "Health check" security: [] responses: "200": description: "Service is healthy" content: application/json: schema: type: object properties: status: { type: string, example: "ok" } version: { type: string } timestamp: { type: string, format: date-time }9. MCP-Ready API Pattern
Sección titulada «9. MCP-Ready API Pattern»# Patron para APIs que seran consumidas por agentes via MCP (Ref Doc 03)mcp_api_pattern: discovery: - "Endpoint de descubrimiento: GET /v1/api-schema" - "Descripcion clara en cada endpoint (OpenAPI description)" - "Ejemplos en cada schema" - "Nombres de campos descriptivos (no abreviaciones)"
agent_friendliness: - "Respuestas JSON consistentes y predecibles" - "Errores informativos (el agente necesita entender que salio mal)" - "Campos de tipo/categoria para ayudar al agente a filtrar" - "Limites claros en documentacion (max records, allowed values)"
safety: - "Read-only endpoints separados de write endpoints" - "Write endpoints con confirmation flag para HITL" - "Rate limiting especifico para agentes (mas restrictivo)" - "Audit log de toda accion ejecutada por agente"10. Checklist de API Design
Sección titulada «10. Checklist de API Design»api_design_checklist: contract: - "[ ] OpenAPI spec escrito ANTES del codigo" - "[ ] Todos los endpoints documentados con descripcion y ejemplos" - "[ ] Request/Response schemas definidos con validacion" - "[ ] Error codes estandarizados" - "[ ] Versionado definido (URL path)"
implementation: - "[ ] Paginacion en todos los list endpoints" - "[ ] Filtrado y busqueda soportados" - "[ ] Rate limiting configurado por plan" - "[ ] Auth + tenant isolation en todo endpoint" - "[ ] Input validation en todo request" - "[ ] Health check endpoint: GET /health"
ai_endpoints: - "[ ] /ai/chat con soporte streaming (SSE)" - "[ ] /ai/analyze para analisis genericos" - "[ ] Semantic cache integrado" - "[ ] Budget guard por tenant" - "[ ] Disclaimer en toda respuesta IA" - "[ ] Sources/citations incluidas"
quality: - "[ ] Tests de contrato (schema validation)" - "[ ] Tests de integracion por endpoint" - "[ ] Performance: p95 < 200ms (non-AI), < 3s (AI)" - "[ ] Security: OWASP API Top 10 revisado" - "[ ] Documentation publicada y actualizada"
operations: - "[ ] Observability: traces por request (Ref Doc 09)" - "[ ] Monitoring: latency, error rate, throughput" - "[ ] Alertas: error rate > 5%, p95 > threshold" - "[ ] Logs estructurados con request_id y tenant_id"Referencias Cruzadas
Sección titulada «Referencias Cruzadas»| Tema | Documento |
|---|---|
| Domain Model (schemas) | Doc 19 --- Data Architecture & Domain Modeling |
| Auth & Tenant Isolation | Doc 08 --- Backup, DR, Database & Auth |
| MCP Server Integration | Doc 03 --- MCP Servers & Conectores |
| Guardrails for AI endpoints | Doc 04 --- Patrones Agenticos |
| Observability per request | Doc 09 --- Observabilidad, FinOps & Alertas |
| Semantic Cache | Doc 18 --- Semantic Cache & Performance AI |
| Compliance (PII, GDPR) | Doc 11 --- Compliance, Regulacion & ISO |
| UX consuming APIs | Doc 15 --- UX/AI Experience Design |
| Multi-Country formatting | Doc 21 --- Multi-Country & Internationalization |
AI-First Engineering Framework --- Baseline v6.5