How to submit tax reporting data to AEAT with curl using Redtrust certificates
Overview
This guide explains how to send VAT (IVA) information and invoice records to the Spanish Tax Agency (AEAT) using curl, from both Windows and Linux environments. It focuses on the two main reporting mechanisms currently in use in Spain:
- Suministro Inmediato de Información (SII), for near-real-time VAT ledger reporting.
- Veri*Factu, for transmitting verifiable invoice records generated by compliant invoicing systems.
The examples assume that you already have the certificate available in Redtrust and that you understand which system (SII, Veri*Factu, or both) applies to your scenario. This guide assumes familiarity with HTTPS, certificates, and basic command-line usage.
Background
Spain is implementing real-time or near-real-time tax reporting mechanisms to improve the traceability of economic transactions and reduce tax fraud. As part of this effort, AEAT provides web services that accept structured data over secure HTTPS connections.
Two complementary mechanisms are relevant in this context:
- SII requires certain taxpayers to submit VAT ledger entries derived from issued and received invoices within short deadlines. The data represents accounting and tax information, not the invoice document itself.
- Veri*Factu regulates how invoices are generated and recorded by invoicing systems, and allows (or requires, depending on the setup) the transmission of invoice records to AEAT at the time of issuance.
From a technical perspective, both systems rely on authenticated HTTP requests, and use mutual TLS (client authentication with an X.509 certificate), structured XML payloads (depending on the service) and dedicated AEAT endpoints.
Because AEAT exposes these services over standard web protocols, you can interact with them using a generic tool such as curl. This guide focuses on SII requests; Veri*Factu examples follow the same pattern.
Before you start
- Windows
- Linux
- Redtrust agent for Windows
curland Schannel
- Redtrust agent for Linux (Ubuntu 22.04)
pkcs11-toolcurlversion > 8.17.0 and OpenSSL version > 3.0.12
Step 1: Check the prerequisites
- Windows
- Linux
In order for curl to use the certificate storage on Windows, curl has to use Schannel.
Execute the command to check that it is installed.
curl -V
The output has to include Schannel.
curl 8.9.1 (Windows) libcurl/8.9.1 Schannel zlib/1.3 WinIDN
Release-Date: 2024-07-31
Protocols: dict file ftp ftps http https imap imaps ipfs ipns mqtt pop3 pop3s smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS HSTS HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM SPNEGO SSL SSPI threadsafe Unicode UnixSockets
To check the prerequisites, run:
curl -V
The output will show the installed version of curl.
curl 8.17.0 (x86_64-pc-linux-gnu) libcurl/8.17.0 OpenSSL/3.0.12
Step 2: Find the certificate thumbprint
- Windows
- Linux
You can find the thumbprint in the Certificates of the admin console.
You can also list the certificates from the powershell CLI. To do that, you need to have the windows agent installed and the user logged in.
Get-ChildItem Cert:\CurrentUser\My
You can find the thumbprint using pkcs11-tool. Use the following command to list the available certificates to the logged-in user.
pkcs11-tool --module /usr/lib/libkeyfactorpkcs11.so --list-objects
Using slot 0 with a present token (0x0)
Certificate Object; type = X.509 cert
label: D8B6D009411BC734AC9F12858C46EC63C73D959D - Certificate
subject: DN: C=ES/serialNumber=IDCES-43465515E, GN=JUAN, SN=GARCIA, CN=GARCIA JUAN
ID: d8b6d009411bc734ac9f12858c46ec63c73d959d
Public Key Object; RSA 2048 bits
label: D8B6D009411BC734AC9F12858C46EC63C73D959D - Public key
ID: d8b6d009411bc734ac9f12858c46ec63c73d959d
Usage: encrypt, verify, wrap
Access: none
Private Key Object; RSA
label: D8B6D009411BC734AC9F12858C46EC63C73D959D - Private key
ID: d8b6d009411bc734ac9f12858c46ec63c73d959d
Usage: decrypt, sign, unwrap
Access: sensitive, extractable
Step 3 (Linux only): Configure OpenSSL to use the Redtrust PKCS#11 engine
-
Locate the OpenSSL configuration file at
/etc/ssl/openssl.cnf. -
Create a copy of the file, for example in your home directory.
cp /etc/ssl/openssl.cnf $HOME/openssl-redtrust.cnf -
Edit the copied configuration file and add the following sections to enable the OpenSSL engine framework.
openssl_conf = openssl_init
[openssl_init]
engines = engine_section
[engine_section]
redtrust = redtrust_engine
[redtrust_engine]
engine_id = redtrust
# Path to the OpenSSL PKCS#11 engine (pkcs11.so).
# Examples:
# - /usr/lib/x86_64-linux-gnu/engines-3/pkcs11.so
# - /usr/lib64/engines-3/pkcs11.so
dynamic_path = OPENSSL_ENGINES_DIR/pkcs11.so
# Path to the Redtrust PKCS#11 module (libkeyfactorpkcs11.so).
# Examples:
# - /usr/lib/libkeyfactorpkcs11.so
# - /usr/local/lib/libkeyfactorpkcs11.so
MODULE_PATH = REDTRUST_PKCS11_MODULE_PATH/libkeyfactorpkcs11.so
init = 1By adding the
openssl_confandenginessections, you tell OpenSSL to load external cryptographic engines at startup.tipYou can locate the Redtrust PKCS#11 module using
sudo find /usr /lib /opt -name "libkeyfactorpkcs11.so" 2>/dev/nulland the pkcs11 engine for OpenSSL 3.x usingsudo find /usr /lib /opt -path "*engines-3*" -name "pkcs11.so" 2>/dev/null.If you cannot find the latter, it is possible you need to install
libp11-3andlibengine-pkcs11-openssl. To do that, runsudo apt updateandsudo apt install -y libp11-3 libengine-pkcs11-openssll. -
Tell OpenSSL to use the custom configuration file. Because you are using a copied configuration file, you must explicitly tell OpenSSL to use it. Set the OPENSSL_CONF environment variable:
export OPENSSL_CONF=$HOME/openssl-redtrust.cnf -
Verify the Redtrust engine configuration:
openssl engine -t -cIf the configuration is correct, the output includes an entry similar to the following:
(rdrand) Intel RDRAND engine
[RAND]
[ available ]
(dynamic) Dynamic engine loading support
[ unavailable ]
(redtrust) pkcs11 engine
[ available ]If the engine appears as available, OpenSSL can successfully load the Redtrust PKCS#11 engine and use it for cryptographic operations required to authenticate transmissions of information sent to the SII.
Step 4: Send the SII information with curl
- Windows
- Linux
Once you have identified the certificate (D8B6D009411BC734AC9F12858C46EC63C73D959D in this example), you can use the following command to send the information.
curl --connect-timeout 60 -m 60 -s -S -L --header "Content-Type: text/xml;charset=UTF-8" --cert "CurrentUser\My\D8B6D009411BC734AC9F12858C46EC63C73D959D" --data-binary "@path\file.xml" "https://prewww1.aeat.es/wlpl/SSII-FACT/ws/fe/SiiFactFEV1SOAP"
Note that this example uses the AEAT pre-production URL. For production, keep the same path and switch to the production host (https://www1.agenciatributaria.gob.es). For the full list of production endpoints (and the corresponding WSDLs), see the official AEAT web service WSDL page.
This command uses the certificate for authentication, and the corresponding operation is logged as an event in Redtrust.
Once you have identified the certificate (D8B6D009411BC734AC9F12858C46EC63C73D959D in this example), you can use the following command to send the information.
curl --engine redtrust --key-type ENG
--cert "redtrust:object=D8B6D009411BC734AC9F12858C46EC63C73D959D - Certificate;type=cert"
--key "redtrust:object=D8B6D009411BC734AC9F12858C46EC63C73D959D - Private key;type=private"
--header "Content-Type: text/xml;charset=-binary @$HOME/path-to-file/invoice.xml"
"https://prewww1.aeat.es/wlpl/SSII-FACT/ws/fe/SiiFactFEV1SOAP"
Note that this example uses the AEAT pre-production URL. For production, keep the same path and switch to the production host (https://www1.agenciatributaria.gob.es). For the full list of production endpoints (and the corresponding WSDLs), see the official AEAT web service WSDL page.
This command uses the certificate for authentication, and the corresponding operation is logged as an event in Redtrust.