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 or 24.04)
curlbuilt against OpenSSL 3p11-kit, to check that the PKCS#11 module is registeredopensc, which includespkcs11-tool
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 response 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
Check the curl version and the TLS library it's built against:
curl -V
curl 8.5.0 (x86_64-pc-linux-gnu) libcurl/8.5.0 OpenSSL/3.0.13 zlib/1.3
curl must be built against OpenSSL. The version determines which component you install in step 3: this response shows 8.5.0, earlier than 8.12, so the engine applies.
Next, check that p11-kit recognizes the Redtrust PKCS#11 module:
p11-kit list-modules
The response includes the keyfactor module and the Redtrust for Linux token.
keyfactor: /usr/lib/libkeyfactorpkcs11.so
library-description: Redtrust PKCS11
library-manufacturer: Evolium
library-version: 3.50
token: Redtrust for Linux
manufacturer: Evolium
model: Linux
The agent installer creates this registration automatically.
If the module isn't listed, check these two causes in order.
-
The registration symlink doesn't exist, because you installed p11-kit after the agent. The installer only creates the symlink if the modules directory is already present. Create it manually:
sudo ln -s /etc/keyfactor/keyfactor.module /usr/share/p11-kit/modules/keyfactor.module -
The symlink exists, but your user doesn't have the agent configured yet. The module needs the configuration in
~/.keyfactorto initialize, and p11-kit silently drops modules that fail to initialize, so the token never appears. Check the configuration withkeyfactor-setup test, always withoutsudo.
Step 2: Identify the certificate
- 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 certificates assigned to your 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
To use the certificate with curl you need its pkcs11: URI, which identifies the object within the token. Build it from these three components:
pkcs11:token=Redtrust%20for%20Linux;object=LABEL;type=cert
token: The token name, alwaysRedtrust for Linux.object: The object label, which is thelabelfield from the previous response.type:certfor the certificate andprivatefor the private key.
pkcs11: URIs are percent-encoded, so replace every space in the label with %20. The label D8B6D009411BC734AC9F12858C46EC63C73D959D - Certificate becomes:
pkcs11:token=Redtrust%20for%20Linux;object=D8B6D009411BC734AC9F12858C46EC63C73D959D%20-%20Certificate;type=cert
Always identify the object by object, never by id. The module returns padded identifiers, and curl can't load the private key when the URI uses id=.
Step 3 (Linux only): Let curl reach the PKCS#11 token
The agent installer registers the Redtrust PKCS#11 module in p11-kit, so you don't need to declare the library path in openssl.cnf or in any other application. You only need to install the component OpenSSL uses to reach p11-kit, which depends on the curl version you checked in step 1.
curlversions earlier than 8.12: Install the OpenSSL PKCS#11 engine.curl8.12 or later: Install the OpenSSL 3 PKCS#11 provider.
Ubuntu 22.04 and 24.04 ship curl versions earlier than 8.12, so the engine is the applicable method on those distributions.
To install the engine, run:
sudo apt install -y libengine-pkcs11-openssl
To install the provider, run:
sudo apt install -y pkcs11-provider
In both cases the component discovers the Redtrust module through p11-kit by default, so there's nothing else to configure.
OpenSSL engines are deprecated as of OpenSSL 3 and the provider is their official replacement. Even so, curl doesn't support pkcs11: URIs through providers until version 8.12, so the engine is still required on earlier versions.
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. Replace FILE_PATH with the path to the XML file you want to send.
curl --connect-timeout 60 -m 60 -s -S -L --header "Content-Type: text/xml;charset=UTF-8" --cert "CurrentUser\My\D8B6D009411BC734AC9F12858C46EC63C73D959D" --data-binary "@FILE_PATH\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.
Once you have identified the certificate (D8B6D009411BC734AC9F12858C46EC63C73D959D in this example), you can use the following command to send the information. Replace FILE_PATH with the path to the XML file you want to send.
curl --engine pkcs11 --cert-type ENG --key-type ENG \
--cert "pkcs11:token=Redtrust%20for%20Linux;object=D8B6D009411BC734AC9F12858C46EC63C73D959D%20-%20Certificate;type=cert" \
--key "pkcs11:token=Redtrust%20for%20Linux;object=D8B6D009411BC734AC9F12858C46EC63C73D959D%20-%20Private%20key;type=private" \
--header "Content-Type: text/xml;charset=UTF-8" \
--data-binary "@FILE_PATH/invoice.xml" \
"https://prewww1.aeat.es/wlpl/SSII-FACT/ws/fe/SiiFactFEV1SOAP"
If you installed the provider instead of the engine, because your curl version is 8.12 or later, omit the --engine, --cert-type, and --key-type options. The rest of the command doesn't change, because curl loads the provider automatically when it receives a pkcs11: URI.
curl --cert "pkcs11:token=Redtrust%20for%20Linux;object=D8B6D009411BC734AC9F12858C46EC63C73D959D%20-%20Certificate;type=cert" \
--key "pkcs11:token=Redtrust%20for%20Linux;object=D8B6D009411BC734AC9F12858C46EC63C73D959D%20-%20Private%20key;type=private" \
--header "Content-Type: text/xml;charset=UTF-8" \
--data-binary "@FILE_PATH/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. The private key never leaves Redtrust, because the agent performs the TLS handshake signature against the server.
Summary
You've submitted tax reporting data to AEAT with curl, authenticating the connection with a certificate that stays in Redtrust. On Windows, curl takes the certificate from the system store through Schannel. On Linux it takes it from the agent's PKCS#11 token through p11-kit, using either the OpenSSL engine or the provider depending on your curl version. In both cases the private key never leaves Redtrust, and every use is logged as an event.
Next steps
- Install and configure the agent on Linux — Configure the agent and enroll additional users on the system.
- Configure SSH key-based authentication — Use the same PKCS#11 module to authenticate over SSH.
- Unattended signing of documents with AutoFirma — Sign documents with Redtrust certificates without user interaction.
Was this page helpful?