Especificación de API REST

Documentación completa de endpoints y ejemplos de uso

Version 1.0 ChatElectoral Generado: 29/04/2026 17:54

Capítulo 1: Introducción a la API

La API REST de ayuntamientosmart.com proporciona acceso programático a las principales funcionalidades del sistema. Está diseñada siguiendo los principios REST (Representational State Transfer) y utiliza los métodos HTTP estándar:

Todas las peticiones y respuestas utilizan formato JSON. Las fechas se expresan en formato ISO 8601 (YYYY-MM-DDTHH:mm:ss). Los errores devuelven códigos HTTP estándar (400, 401, 403, 404, 500) con un objeto JSON descriptivo.

Capítulo 2: Autenticación

La API utiliza autenticación basada en JWT (JSON Web Tokens). El flujo de autenticación es:

Obtención del token

Endpoint: POST /api/v1/auth/login

{
  "usuario": "agente123",
  "password": "mi_password_segura"
}

Respuesta exitosa (200 OK):

{
  "success": true,
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expires_at": "2026-01-11T15:30:00",
    "usuario": {
      "id": "usr-123",
      "nombre": "Juan Pérez",
      "rol": "agente"
    }
  }
}

Uso del token

Una vez obtenido el token, debe incluirse en todas las peticiones en la cabecera Authorization:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Renovación del token

Los tokens expiran a las 24 horas. Puede renovarse sin necesidad de reautenticarse:

Endpoint: POST /api/v1/auth/refresh

Incluya el token actual en la cabecera Authorization. Devolverá un nuevo token con 24 horas adicionales de validez.

Capítulo 3: Formato de respuestas

Todas las respuestas de la API siguen un formato estándar:

Respuesta exitosa

{
  "success": true,
  "data": { /* Datos solicitados */ },
  "meta": { /* Metadatos opcionales: paginación, totales, etc. */ }
}

Respuesta de error

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Descripción legible del error",
    "details": { /* Detalles específicos del error */ }
  }
}

Códigos HTTP

Capítulo 4: Endpoints de Denuncias

Listar denuncias

GET /api/v1/denuncias

Parámetros query opcionales:

Ejemplo:

GET /api/v1/denuncias?tipo=hechos&desde=2026-01-01&limit=50

Respuesta:

{
  "success": true,
  "data": [
    {
      "id": "DEN-2026-00001",
      "tipo": "hechos",
      "fecha": "2026-01-10T10:30:00",
      "denunciante": {
        "nombre": "María García",
        "dni": "12345678A"
      },
      "hechos": "Hurto de móvil en vía pública",
      "estado": "registrada"
    },
    /* ... más denuncias ... */
  ],
  "meta": {
    "total": 250,
    "page": 1,
    "limit": 50,
    "pages": 5
  }
}

Obtener una denuncia específica

GET /api/v1/denuncias/{id}

Ejemplo:

GET /api/v1/denuncias/DEN-2026-00001

Devuelve todos los detalles de la denuncia incluyendo denunciante, denunciados, testigos, adjuntos, historial de cambios.

Crear una denuncia

POST /api/v1/denuncias

Body JSON:

{
  "tipo": "perdida",
  "denunciante": {
    "dni": "12345678A",
    "nombre": "Juan López",
    "telefono": "666123456",
    "email": "juan@example.com",
    "direccion": "Calle Mayor 1, 28001 Madrid"
  },
  "hechos": {
    "fecha": "2026-01-10",
    "hora": "14:30",
    "lugar": "Plaza España, Madrid",
    "descripcion": "Extravié mi cartera con DNI y tarjetas bancarias"
  },
  "objetos_perdidos": [
    {
      "tipo": "documento",
      "descripcion": "DNI 12345678A"
    },
    {
      "tipo": "otro",
      "descripcion": "Cartera de piel negra con tarjetas Visa y Mastercard"
    }
  ]
}

Respuesta (201 Created):

{
  "success": true,
  "data": {
    "id": "DEN-2026-00125",
    "fecha_creacion": "2026-01-10T15:45:00",
    "estado": "registrada"
  }
}

Actualizar una denuncia

PATCH /api/v1/denuncias/{id}

Solo pueden actualizarse denuncias en estado 'borrador'. Body JSON con los campos a modificar.

Eliminar una denuncia

DELETE /api/v1/denuncias/{id}

Marca la denuncia como eliminada (soft delete). Requiere permiso especial.

Capítulo 5: Endpoints de Sanciones

Listar sanciones

GET /api/v1/sanciones

Parámetros query similares a denuncias más:

Obtener una sanción

GET /api/v1/sanciones/{id}

Crear una sanción

POST /api/v1/sanciones

Body JSON:

{
  "tipo": "in_situ",
  "vehiculo": {
    "matricula": "1234ABC"
  },
  "conductor": {
    "dni": "98765432B",
    "permiso": "ES987654321"
  },
  "infraccion": {
    "codigo": "3.1",
    "fecha": "2026-01-10",
    "hora": "16:30",
    "lugar": "Calle Alcalá 100, Madrid",
    "descripcion": "Circular por sentido contrario"
  },
  "agente": "TIP123"
}

El sistema consulta automáticamente DGT para validar vehículo y conductor, calcula importe y puntos según la infracción, y genera el boletín.

Registrar pago de sanción

POST /api/v1/sanciones/{id}/pagos

Body JSON:

{
  "fecha": "2026-01-15",
  "importe": 100.00,
  "forma_pago": "tarjeta",
  "referencia": "OP123456789"
}

Capítulo 6: Endpoints de Vehículos

Consultar vehículo en DGT

GET /api/v1/vehiculos/dgt/{matricula}

Consulta en tiempo real los datos del vehículo en la DGT. Requiere integración TESTRA activa.

Respuesta:

{
  "success": true,
  "data": {
    "matricula": "1234ABC",
    "marca": "SEAT",
    "modelo": "IBIZA",
    "bastidor": "VF1XXXXXXXXXXXX",
    "fecha_matriculacion": "2020-05-15",
    "titular": {
      "nombre": "JOSE MARTINEZ GARCIA",
      "dni": "11223344X",
      "direccion": "CALLE EJEMPLO 1, 28001 MADRID"
    },
    "itv": {
      "fecha_ultima": "2025-05-10",
      "resultado": "FAVORABLE",
      "fecha_caducidad": "2027-05-10"
    },
    "seguro": {
      "compania": "MAPFRE",
      "poliza": "ES123456789",
      "vigente": true
    }
  }
}

Consultar conductor

GET /api/v1/vehiculos/dgt/conductor/{permiso}

Consulta datos del permiso de conducir en DGT.

Ejemplos de uso

Ejemplos prácticos de integración con la API en diferentes lenguajes de programación.

JavaScript / Node.js

// Autenticación
const axios = require('axios');
const API_URL = 'https://municipio.ayuntamientosmart.com/api/v1';

async function login(usuario, password) {
  const response = await axios.post(`${API_URL}/auth/login`, {
    usuario,
    password
  });
  return response.data.data.token;
}

// Listar denuncias
async function getDenuncias(token) {
  const response = await axios.get(`${API_URL}/denuncias`, {
    headers: {
      'Authorization': `Bearer ${token}`
    },
    params: {
      tipo: 'hechos',
      limit: 50
    }
  });
  return response.data.data;
}

// Uso
const token = await login('agente123', 'password');
const denuncias = await getDenuncias(token);
console.log(denuncias);

Python

import requests
import json

API_URL = 'https://municipio.ayuntamientosmart.com/api/v1'

# Autenticación
def login(usuario, password):
    response = requests.post(
        f'{API_URL}/auth/login',
        json={'usuario': usuario, 'password': password}
    )
    return response.json()['data']['token']

# Crear denuncia
def crear_denuncia(token, datos):
    response = requests.post(
        f'{API_URL}/denuncias',
        headers={'Authorization': f'Bearer {token}'},
        json=datos
    )
    return response.json()

# Uso
token = login('agente123', 'password')
denuncia = crear_denuncia(token, {
    'tipo': 'perdida',
    'denunciante': {
        'dni': '12345678A',
        'nombre': 'Juan López',
        'telefono': '666123456'
    },
    'hechos': {
        'fecha': '2026-01-10',
        'lugar': 'Plaza España',
        'descripcion': 'Pérdida de cartera'
    }
})
print(denuncia)

PHP

<?php
$API_URL = 'https://municipio.ayuntamientosmart.com/api/v1';

// Autenticación
function login($usuario, $password) {
    global $API_URL;
    $ch = curl_init("$API_URL/auth/login");
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
        'usuario' => $usuario,
        'password' => $password
    ]));
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($ch);
    $data = json_decode($response, true);
    return $data['data']['token'];
}

// Consultar vehículo
function consultarVehiculo($token, $matricula) {
    global $API_URL;
    $ch = curl_init("$API_URL/vehiculos/dgt/$matricula");
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $token
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($ch);
    return json_decode($response, true);
}

// Uso
$token = login('agente123', 'password');
$vehiculo = consultarVehiculo($token, '1234ABC');
print_r($vehiculo);
?>

cURL (línea de comandos)

# Autenticación
curl -X POST https://municipio.ayuntamientosmart.com/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"usuario":"agente123","password":"password"}'

# Guardar token
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

# Listar denuncias
curl -X GET "https://municipio.ayuntamientosmart.com/api/v1/denuncias?limit=10" \
  -H "Authorization: Bearer $TOKEN"

# Crear denuncia
curl -X POST https://municipio.ayuntamientosmart.com/api/v1/denuncias \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d @denuncia.json

Límites y cuotas

Para garantizar la estabilidad del servicio, la API implementa límites de peticiones (rate limiting).

Límites por usuario

Cada token JWT tiene los siguientes límites:

  • 1000 peticiones/hora para endpoints de lectura (GET)
  • 100 peticiones/hora para endpoints de escritura (POST, PUT, PATCH, DELETE)
  • 10 peticiones/minuto para consultas a DGT (endpoints /vehiculos/dgt/*)

Si se excede el límite, la API devuelve código 429 Too Many Requests con una cabecera Retry-After indicando cuántos segundos esperar.

Cabeceras de rate limit

Cada respuesta incluye cabeceras informativas:

  • X-RateLimit-Limit: Límite total de peticiones
  • X-RateLimit-Remaining: Peticiones restantes en el periodo actual
  • X-RateLimit-Reset: Timestamp Unix cuando se resetea el contador

Monitorice estas cabeceras para evitar alcanzar el límite.

Límites aumentados

Si necesita límites superiores para integraciones críticas o con alto volumen, contacte con soporte técnico. Es posible aumentar los límites previa justificación y análisis de impacto en el sistema.

Webhooks

Además de la API REST de petición-respuesta, el sistema soporta webhooks para notificar eventos en tiempo real a sistemas externos.

Configuración de webhooks

Desde el panel de administración, puede configurar URLs de webhook que serán invocadas cuando ocurran eventos específicos. Configure:

  • URL de destino (debe ser HTTPS)
  • Eventos a escuchar (denuncia.creada, sancion.pagada, etc.)
  • Secret para validar la firma HMAC de las peticiones

Eventos disponibles

Eventos que pueden suscribirse:

  • denuncia.creada
  • denuncia.modificada
  • denuncia.eliminada
  • sancion.creada
  • sancion.pagada
  • sancion.alegacion_presentada
  • atestado.creado
  • atestado.enviado_lexnet

Formato de payload

Cuando ocurre un evento, se envía un POST a la URL configurada con JSON:

{
  "event": "denuncia.creada",
  "timestamp": "2026-01-10T15:30:00Z",
  "data": {
    "id": "DEN-2026-00123",
    /* ... datos del objeto ... */
  }
}

La petición incluye cabecera X-Webhook-Signature con firma HMAC-SHA256 del payload usando el secret configurado.

Validación de firma

Para verificar que el webhook proviene realmente del sistema:

const crypto = require('crypto');

function validarWebhook(payload, signature, secret) {
  const hash = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');
  return hash === signature;
}

Versionado de la API

La API utiliza versionado semántico para mantener compatibilidad hacia atrás mientras evoluciona con nuevas funcionalidades.

Versión actual

La versión actual es v1 (disponible en /api/v1/). Esta versión se mantendrá estable y compatible hacia atrás. Cualquier cambio que rompa compatibilidad se publicará como una nueva versión (v2, v3, etc.).

Cambios compatibles

Se consideran cambios compatibles (pueden hacerse en la misma versión):

  • Añadir nuevos endpoints
  • Añadir nuevos campos opcionales en las respuestas
  • Añadir nuevos parámetros opcionales en las peticiones
  • Añadir nuevos códigos de error

Cambios incompatibles

Cambios que requieren nueva versión:

  • Eliminar o renombrar endpoints
  • Eliminar campos de las respuestas
  • Cambiar tipos de datos de campos existentes
  • Hacer obligatorios parámetros que eran opcionales
  • Cambiar el comportamiento de endpoints existentes

Deprecaciones

Antes de eliminar funcionalidad en una nueva versión, se marcará como deprecada en la versión actual durante al menos 6 meses. Las funcionalidades deprecadas incluirán una cabecera de respuesta Warning indicándolo.

Seguridad

La API implementa múltiples capas de seguridad para proteger los datos sensibles municipales.

HTTPS obligatorio

Todas las peticiones deben realizarse por HTTPS (TLS 1.3). Las peticiones HTTP son rechazadas con error 403. Los certificados SSL son validados, no se admiten certificados autofirmados.

Autenticación JWT

Los tokens JWT están firmados con algoritmo HS256 usando clave secreta de 256 bits almacenada de forma segura. Cada token incluye claims: usuario id, rol, permisos, fecha de expiración. Los tokens no pueden modificarse sin invalidar la firma.

Control de permisos

Cada endpoint requiere permisos específicos. El token JWT incluye los permisos del usuario. Si intenta acceder a un endpoint sin permisos, recibe 403 Forbidden. Los permisos se comprueban en cada petición contra el sistema RBAC.

Auditoría completa

Todas las peticiones a la API se registran en el log de auditoría con: usuario, endpoint, parámetros, IP origen, timestamp, resultado. Los logs se conservan 3 años según ENS. Pueden consultarse desde el panel de administración.

Protección contra ataques

Implementado:

  • Rate limiting para prevenir abuso
  • Validación de input contra inyecciones SQL, XSS, etc.
  • Sanitización de parámetros
  • Protección CSRF no necesaria (autenticación stateless con JWT)
  • Cabeceras de seguridad: HSTS, X-Content-Type-Options, X-Frame-Options

Historial de cambios

Version 1.0 - 2026-01-10
  • Versión inicial de la API REST
  • Endpoints de denuncias (CRUD completo)
  • Endpoints de sanciones (CRUD completo)
  • Endpoints de consulta DGT (vehículos y conductores)
  • Autenticación JWT con refresh token
  • Sistema de webhooks para eventos
  • Rate limiting y control de cuotas
  • Documentación completa con ejemplos