Sandbox sobre la preproducción de la AEAT · sin tarjeta · Primera factura en 5 minutos
verifactu.co

Documentación

Documentación de la API

Referencia completa: autenticación, endpoints, el objeto registro campo a campo, los estados de la remisión, el catálogo de errores de la AEAT y las diferencias entre preproducción y producción.

¿Cómo se integra VeriFactu por API?

Envías los datos de la factura a POST /v1/registros con tu clave en la cabecera Authorization. Recibes al instante la huella y la URL del QR para imprimir, y el resultado de la remisión a la AEAT te llega después por webhook o consultando el registro.

La remisión no es síncrona a propósito: la AEAT impone un control de flujo y hay que serializar por emisor para que la cadena de huellas no se bifurque.

01 Autenticación Bearer + idempotencia

Una clave por entorno. Las claves de prueba y las de producción no se pueden mezclar ni por accidente: apuntan a servicios distintos de la AEAT.

Cabeceras
# Toda petición lleva la clave en la cabecera Authorization.
# Las claves sk_test_ pegan contra preproducción de la AEAT;
# las sk_live_ contra producción. Nunca se mezclan.

Authorization: Bearer sk_test_9f2Kq...
Content-Type:  application/json
Idempotency-Key: F2026-0184
Idempotency-Key no es opcional en la práctica. Un reintento de tu lado sin esa cabecera crea un segundo registro con su propia huella, y en una cadena encadenada eso no se deshace. Usa tu número de factura.
02 Endpoints REST sobre JSON
Método y rutaQué hace
POST /v1/registrosDa de alta una factura y la encola para remisión. Devuelve huella y QR al instante.
GET /v1/registros/{id}Estado actual de un registro, con el CSV si ya fue aceptado.
GET /v1/registrosLista paginada. Filtros por emisor, estado, desde y hasta.
POST /v1/registros/{id}/anulacionEmite el registro de anulación. No borra: encadena un registro nuevo.
GET /v1/registros/{id}/xmlEl XML exacto que se remitió a la AEAT, para auditoría.
GET /v1/registros/{id}/cadenaLa cadena literal sometida a SHA-256. Lo primero que hay que mirar ante un rechazo.
POST /v1/emisoresAlta de un NIF emisor, con su modalidad de remisión.
GET /v1/emisoresLista de emisores y su estado ante la AEAT.
POST /v1/webhooksRegistra una URL de destino y devuelve el secreto de firma.
GET /v1/exportacionRegistros y eventos en el XML estandarizado del reglamento.
BASE https://api.verifactu.co/v1todas las rutas cuelgan de aquí
03 El objeto registro Lo que devuelve la API
registro
{
  "id":              "reg_9fK2mQ",
  "objeto":          "registro",
  "emisor":          { "nif": "B12345678", "nombre": "PELUQUERIA DEMO SL" },
  "numero":          "F2026/0184",
  "fecha":           "2026-08-26",
  "tipo":            "F1",
  "impuesto":        "IGIC",
  "base":            100.00,
  "cuota":             7.00,
  "total":           107.00,

  // Calculado por el motor — no se envía en la petición
  "huella":          "3C464DAF61ACB827C65FDA19F352A4E3BDC2C640E9E9FC4CC058073F38F12F60",
  "huella_anterior": "A91C...E4",
  "generado_en":     "2026-08-26T10:15:00+01:00",
  "qr":              "https://www2.agenciatributaria.gob.es/wlpl/TIKE-CONT/ValidarQR?nif=...",

  // Resultado de la remisión
  "estado":          "aceptado",
  "csv":             "A1B2C3D4E5F6",
  "aeat": {
    "estado_envio":  "Correcto",
    "codigo":        null,
    "descripcion":   null
  },
  "intentos":        1,
  "creado_en":       "2026-08-26T10:15:00+01:00"
}
CampoQué es
tipoF1 completa · F2 simplificada · F3 · R1 a R5 rectificativas.
impuestoIVA, IGIC o IPSI.
huellaSHA-256 en hexadecimal MAYÚSCULA del registro.
huella_anteriorLa del registro previo del mismo emisor. Vacía en el primero.
generado_enISO-8601 con huso horario. Entra en la huella y se conserva: el XML declara el mismo instante.
estadopendiente · enviando · aceptado · aceptado_con_errores · rechazado · error.
csvCódigo Seguro de Verificación de la AEAT. Solo si el estado es aceptado.
aeat.estado_envioLiteral de la AEAT: Correcto, AceptadoConErrores o Incorrecto.
04 Estados y errores Qué reintentar y qué no

La distinción que gobierna todo: un rechazo de contenido no se arregla reintentando —solo esconde el problema— mientras que un fallo transitorio hay que reintentarlo o la factura se queda colgada sin que nadie se entere.

EstadoQué significa
pendienteRegistro creado y en cola. Ya tienes huella y QR: puedes imprimir la factura.
enviandoEn curso hacia la AEAT.
aceptadoLa AEAT lo aceptó. Hay CSV.
aceptado_con_erroresAceptado pero con avisos. Suele ser el formato de importes: la AEAT recalculó la huella desde el XML y no le cuadró.
rechazadoRechazo de contenido. No se reintenta. Alguien tiene que corregir un dato.
errorAgotados los seis reintentos de un fallo transitorio. Requiere revisión.
Cuerpo de un rechazo
# 422 Unprocessable Entity
{
  "error": {
    "tipo":     "rechazo_aeat",
    "codigo":   "4104",
    "titulo":   "El nombre del emisor no coincide con el censo",
    "accion":   "Usa la razón social exacta que figura en Hacienda...",
    "quien":    "emisor",
    "aeat":     "<texto literal devuelto por la AEAT>",
    "doc":      "https://verifactu.co/errores-aeat/4104/"
  }
}

Nunca ocultamos el mensaje original de la AEAT: va siempre en error.aeat. Para un código que no tenemos catalogado mostramos su texto literal en vez de inventar una explicación.

05 Entornos Preproducción y producción
PreproducciónProducción
Clavesk_test_…sk_live_…
Servicio de remisiónprewww1.aeat.eswww1.agenciatributaria.gob.es
Certificado de selloprewww10.aeat.eswww10.agenciatributaria.gob.es
Validador del QRprewww2.aeat.eswww2.agenciatributaria.gob.es
El servicio SOAP y el validador del QR son hosts distintos, y confundirlos cuesta un día entero: apuntar la remisión a www2 no da un error claro, simplemente no funciona. Los certificados de sello de entidad además usan otro puerto (www10): con el equivocado ni siquiera llegas a hablar con el servicio.
06 Descargas OpenAPI y Postman

La especificación es la fuente de la verdad, y la colección de Postman se genera a partir de ella: no pueden divergir. Si prefieres un cliente generado en tu lenguaje, genéralo desde el YAML en vez de esperar a que publiquemos un SDK.

FicheroQué es
verifactu-v1.yamlEspecificación OpenAPI 3.1 completa: 10 operaciones, esquemas, ejemplos y catálogo de errores.
verifactu.postman_collection.jsonColección de Postman v2.1, ordenada según el quickstart. Guarda sola el id del registro entre peticiones.
Para usar la colección: impórtala, pon tu clave en la variable api_key y ejecuta la carpeta «Empezar aquí» de arriba abajo. Es el mismo recorrido que el quickstart.
FAQ Preguntas Respuestas directas
¿Hay OpenAPI y colección de Postman?

Sí, las dos se descargan desde esta misma página. La especificación es OpenAPI 3.1 y la colección de Postman se genera a partir de ella, así que no pueden divergir. Cada cambio queda anotado en el changelog.

¿Cómo se versiona la API?

La versión va en la ruta (/v1/). Dentro de una versión solo añadimos campos: nunca quitamos ni renombramos uno existente. Un cambio incompatible sería /v2/ y convivirían.

¿Hay límites de llamadas?

Sí, por clave, y la respuesta los declara en las cabeceras X-RateLimit. Pero el límite que de verdad manda no es el nuestro: es el TiempoEsperaEnvio que impone la AEAT en su control de flujo, y ese lo gestionamos nosotros por ti.

¿Puedo recuperar el XML exacto que se envió?

Sí, en GET /v1/registros/{id}/xml. Y la cadena literal que se sometió a SHA-256 en /cadena. Son las dos cosas que hay que poder mirar cuando algo no cuadra.

Última revisión normativa: Especificaciones de huella AEAT v0.1.2 Revisado por el equipo técnico de verifactu.co