VerifactuMidAPI/documentacion/api.md

5.9 KiB

API Reference

Endpoints

Health

GET /api/v1/health

Verifica que la API está funcionando.

Response:

{"status": "ok"}

Obtener Clave Pública

GET /api/v1/auth/public-key

Obtiene la clave pública RSA para cifrar contraseñas.

Response:

{"public_key": "base64_encoded_key"}

Registrar Certificado

POST /api/v1/auth/register

Registra y valida un certificado digital. El certificado se envía como base64 en el body (no como ruta de fichero).

Request (snake_case):

{
  "cert_name": "mi-certificado",
  "cert_file": "BASE64_CONTENT_OF_P12_FILE",
  "password_encrypted": "base64_encoded_encrypted_password"
}

Request (PascalCase — compatibilidad con frontend):

{
  "CertName": "mi-certificado",
  "CertFile": "BASE64_CONTENT_OF_P12_FILE",
  "PasswordEncrypted": "base64_encoded_encrypted_password"
}

Nota: password_encrypted debe ser la contraseña del certificado cifrada con la clave pública RSA obtenida en /api/v1/auth/public-key. No se envía en texto plano.


**Response (éxito):**
```json
{
  "success": true,
  "cert": {
    "subject": "...",
    "issuer": "...",
    "expired": false,
    "expiring_soon": false,
    "days_until_expiry": 365
  },
  "token": "A1B2C3D4..."
}

Response (error):

{
  "success": false,
  "error": "certificate_expired",
  "cert": {
    "subject": "...",
    "issuer": "...",
    "expired": true
  }
}

Formatos Disponibles

GET /api/v1/formats

Lista los formatos de entrada soportados. La API detecta automáticamente el formato del JSON recibido.

Response:

{
  "formats": ["dolibarr", "native"]
}

Alta de Factura

POST /api/v1/facturas

Registra una factura en VeriFactu. El formato de entrada se detecta automáticamente (no requiere parámetro).

Formato nativo (por defecto):

{
  "tipo": "alta",
  "factura": {
    "emisor_nif": "53950250R",
    "emisor_nombre": "EMPRESA EJEMPLO SL",
    "num_serie": "FV2026/001",
    "fecha_expedicion": "17-04-2026",
    "tipo_factura": "F1",
    "descripcion": "Factura de prueba",
    "destinatario": {
      "nombre": "CLIENTE SL",
      "nif": "B98765432"
    },
    "iva": [
      {"base": 100.00, "cuota": 21.00, "tipo": 21.0}
    ],
    "importe_total": 121.00
  },
  "sistema": {
    "nombre": "Mi Sistema",
    "nif_proveedor": "53950250R",
    "version": "1.0"
  }
}

Formato Dolibarr BFF:

{
  "invoice": {
    "number": "FA2024/001",
    "date": "2024-09-13T00:00:00Z",
    "notePublic": "Factura de prueba",
    "lines": [
      {"description": "Servicio", "quantity": 1, "unitPrice": 100, "taxRate": 21}
    ]
  },
  "client": {
    "name": "CLIENTE SL",
    "vatNumber": "B98765432"
  },
  "emisor": {
    "nif": "53950250R",
    "nombre": "EMPRESA EJEMPLO SL"
  },
  "sistema": {
    "nombre": "Mi Sistema",
    "nif_proveedor": "53950250R",
    "version": "1.0"
  }
}

Ver formatos.md para detalles de cada formato y cómo añadir nuevos.

Response (AEAT disponible):

{
  "success": true,
  "csv": "A-FSZKDA8UG7WD9U",
  "estado": "Correcto"
}

Response (fallback local):

{
  "success": true,
  "csv": "0CE5F940CEA...",
  "estado": "Correcto (local)"
}

Nota: El campo sistema.nombre debe coincidir con el nombre registrado en la AEAT para el NIF del emisor. Si no coincide, la AEAT rechazará la factura con error de censo (código 1110 o 1239).


---

### Anular Factura

POST /api/v1/facturas/anular

Anula una factura previamente registrada. Usa el mismo formato que el alta pero con `tipo: "anulacion"` y `tipo_factura: "R1"` (u otro tipo de rectificativa).

**Request:**
```json
{
  "tipo": "anulacion",
  "factura": {
    "emisor_nif": "53950250R",
    "emisor_nombre": "JOSEP VICENT MESTRE LLOBELL",
    "num_serie": "FV2026/001",
    "fecha_expedicion": "21-05-2026",
    "tipo_factura": "R1",
    "descripcion": "Anulacion de factura de prueba",
    "iva": [
      {"base": 1000.00, "cuota": 210.00, "tipo": 21.0}
    ],
    "importe_total": 1210.00
  },
  "sistema": {
    "nombre": "JOSEP VICENT MESTRE LLOBELL",
    "nif_proveedor": "53950250R",
    "version": "1.0"
  }
}

Response (éxito):

{
  "success": true,
  "estado": "Anulada"
}

Nota: El campo sistema.nombre debe coincidir con el nombre registrado en la AEAT para el NIF del emisor. Si no coincide, la AEAT rechazará la factura con error de censo.


## Códigos de Error

| Código | Descripción |
|--------|------------|
| `certificate_expired` | El certificado ha expirado |
| `certificate_not_yet_valid` | El certificado aún no es válido |
| `certificate_expiring_soon` | El certificado caduca en menos de 30 días |
| `invalid_password_or_format` | Contraseña incorrecta o formato inválido |
| `file_not_found` | El archivo de certificado no existe |
| `validation_failed` | Los datos de la factura no son válidos |
| `aeat_error` | Error comunicando con la AEAT |
| `aeat_fault` | Error SOAP de la AEAT |
| `hash_save_error` | Error guardando el hash local |
| `hash_storage_error` | Error leyendo el hash anterior |
| `missing_fields` | Faltan campos obligatorios en el registro |
| `invalid_json` | El JSON enviado no es válido |
| `decrypt_failed` | No se pudo descifrar la contraseña con la clave privada |
| `emisor_nif_required` | Falta el NIF del emisor en la anulación |
| `num_serie_required` | Falta el número de serie en la anulación |
| `fecha_expedicion_required` | Falta la fecha de expedición en la anulación |

## Errores de la AEAT más comunes

| Código | Descripción | Solución |
|--------|------------|----------|
| 1110 | NIF no identificado en el censo | Verificar que `sistema.nombre` coincide con el nombre del NIF |
| 1189 | Bloque Destinatarios obligatorio para tipo F1/F3/R1-R4 | Incluir `destinatario` con nombre y NIF |
| 1239 | Error en bloque Destinatario | Verificar formato del NIF del destinatario |