Spain Fiscalization Guide
Spain has three fiscalization systems. FiscalAPI supports all of them:
- TicketBAI -- Real-time invoice reporting for the Basque Country
- Verifactu -- Invoice verification for the rest of Spain
- SII -- Real-time invoice reporting for large businesses (annual revenue >= EUR 6M)
TicketBAI vs Verifactu vs SII
| Feature | TicketBAI | Verifactu | SII |
|---|---|---|---|
| Scope | Basque Country territories | All of Spain | Large businesses (>= EUR 6M) |
| Territories | Gipuzkoa, Araba, Bizkaia | Nationwide | Nationwide |
| Authority | Regional tax authorities | AEAT (national) | AEAT (national) |
| Submission | Real-time XML (Gipuzkoa/Araba) or LROE batch (Bizkaia) | SOAP to AEAT | SOAP to AEAT |
| Signing | XAdES-EPES | SHA-256 hash chaining | Mutual TLS |
| Deadline | Real-time | Real-time | 4 calendar days |
| Status | Active (mandatory in Basque Country) | Rolling out | Active |
When to use TicketBAI
Use TicketBAI for merchants operating in the Basque Country:
- Gipuzkoa -- Real-time XML POST with XAdES-EPES signature
- Araba -- Real-time XML POST with XAdES-EPES signature
- Bizkaia -- LROE batch submission (daily at 2 AM UTC)
When to use Verifactu
Use Verifactu for merchants operating in the rest of Spain or for nationwide compliance. Verifactu submits invoices via SOAP to AEAT with SHA-256 hash chaining for invoice integrity.
When to use SII
Use SII for large businesses with annual turnover exceeding EUR 6,336,000, businesses enrolled in the monthly VAT refund scheme (REDEME), or groups filing consolidated VAT returns. SII submits invoice records to AEAT via SOAP with mutual TLS authentication within a four-day window. See the SII guide for full details.
Country config fields
The country_config object for Spanish locations supports the following fields:
Common fields
| Field | Type | Required | Description |
|---|---|---|---|
system | string | Yes | ticketbai, verifactu, or sii |
nif | string | Yes | Spanish tax ID (NIF/CIF) |
legal_name | string | Yes | Company legal name |
certificate_id | string | Yes | Reference to an uploaded certificate |
tsa_url | string | No | RFC 3161 TSA endpoint for XAdES-T timestamps |
TicketBAI fields
| Field | Type | Required | Description |
|---|---|---|---|
territory | string | Yes | gipuzkoa, araba, or bizkaia |
tbai_license | string | Yes | TicketBAI software license code |
Verifactu fields
| Field | Type | Required | Description |
|---|---|---|---|
software_nif | string | Yes | Software developer's NIF |
installation_number | string | No | Verifactu installation identifier |
SII fields
SII configuration is simpler -- it requires only the NIF and legal name. See the SII guide for full configuration and metadata details.
| Field | Type | Required | Description |
|---|---|---|---|
nif | string | Yes | Spanish tax ID (NIF/CIF) of the obligated party |
legal_name | string | Yes | Full legal name (razón social) |
certificate_id | string | Yes | Reference to an uploaded certificate for mutual TLS |
Configuration examples
TicketBAI location (Gipuzkoa)
curl -X POST https://api.fiscalapi.com/v1/locations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer fsk_test_abc123def456..." \
-d '{
"name": "Donostia Store",
"country": "ES",
"address": "Calle Mayor 1, 20003 San Sebastián",
"tax_id": "B12345674",
"country_config": {
"system": "ticketbai",
"territory": "gipuzkoa",
"nif": "B12345674",
"legal_name": "Acme Corp SL",
"certificate_id": "spain-prod-2026",
"tbai_license": "TBAILIC123456"
}
}'
TicketBAI location (Bizkaia)
Bizkaia uses LROE batch submission instead of real-time. Transactions are queued with pending_lroe status and submitted in batches (daily at 2 AM UTC).
curl -X POST https://api.fiscalapi.com/v1/locations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer fsk_test_abc123def456..." \
-d '{
"name": "Bilbao Store",
"country": "ES",
"address": "Gran Vía de Don Diego López de Haro 1, 48001 Bilbao",
"tax_id": "B12345674",
"country_config": {
"system": "ticketbai",
"territory": "bizkaia",
"nif": "B12345674",
"legal_name": "Acme Corp SL",
"certificate_id": "spain-prod-2026",
"tbai_license": "TBAILIC123456"
}
}'
Verifactu location
curl -X POST https://api.fiscalapi.com/v1/locations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer fsk_test_abc123def456..." \
-d '{
"name": "Barcelona Store",
"country": "ES",
"address": "Passeig de Gracia 1, 08007 Barcelona",
"tax_id": "B87654321",
"country_config": {
"system": "verifactu",
"nif": "B87654321",
"legal_name": "Acme Corp SL",
"certificate_id": "spain-prod-2026",
"software_nif": "B99999999",
"installation_number": "001"
}
}'
SII location
curl -X POST https://api.fiscalapi.com/v1/locations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer fsk_test_abc123def456..." \
-d '{
"name": "Madrid HQ",
"country": "ES",
"address": "Calle de Alcalá 50, 28014 Madrid",
"tax_id": "A12345674",
"country_config": {
"system": "sii",
"nif": "A12345674",
"legal_name": "Gran Empresa SL",
"certificate_id": "spain-sii-prod-2026"
}
}'
Submission flows
TicketBAI (Gipuzkoa / Araba)
- Transaction is created via
POST /v1/transactions - FiscalAPI generates the TicketBAI XML with invoice chaining (per-NIF)
- XML is signed with XAdES-EPES using the uploaded certificate
- Signed XML is POSTed to the regional tax authority in real-time
- On success,
fiscal_id(TBAI ID) is set and a QR code URL is generated - Transaction status transitions to
success
TicketBAI (Bizkaia -- LROE)
- Transaction is created via
POST /v1/transactions - Inline XML generation and signing succeeds
- Transaction status transitions to
pending_lroe(not yet submitted) - LROE batch processor collects pending transactions and submits them as a batch
- On acceptance, transaction status transitions to
success
You can monitor LROE batch processing via the batch stats endpoint.
Verifactu
- Transaction is created via
POST /v1/transactions - FiscalAPI generates the Verifactu record with SHA-256 hash chaining
- Record is submitted via SOAP to AEAT
- On success,
fiscal_idis set and transaction status transitions tosuccess
SII
- Transaction is created via
POST /v1/transactions - FiscalAPI builds a SOAP envelope with the invoice record
- Envelope is submitted to AEAT via mutual TLS
- AEAT responds with a status and CSV (Código Seguro de Verificación)
- On success,
fiscal_idis set to the CSV and transaction status transitions tosuccess
Invoices must be reported within four calendar days. See the SII guide for metadata fields, book types, and endpoint details.
Invoice chaining
Both TicketBAI and Verifactu use invoice chaining to ensure integrity. Each invoice references the hash of the previous invoice for the same NIF, creating a tamper-evident chain. FiscalAPI manages this automatically -- you don't need to track chain state.
Switching systems
You can change a location's fiscalization system using the update endpoint:
curl -X PATCH https://api.fiscalapi.com/v1/locations/{id} \
-H "Content-Type: application/json" \
-H "Authorization: Bearer fsk_test_abc123def456..." \
-d '{
"country_config": {
"system": "verifactu",
"nif": "B12345674",
"legal_name": "Acme Corp SL",
"certificate_id": "spain-prod-2026",
"software_nif": "B99999999"
}
}'
Validation rules
FiscalAPI enforces these rules for Spanish locations:
country_configis required -- Spain locations must include acountry_configwith asystemfield- Valid systems --
systemmust beticketbai,verifactu, orsii - Territory -- Required for TicketBAI; must be
gipuzkoa,araba, orbizkaia - NIF -- Spanish tax ID (CIF/NIF) for the merchant
- Legal name -- Required for SII (the obligated party's full legal name)
- Certificate -- A valid signing certificate must be uploaded and referenced by
certificate_id
Error examples
Missing country config:
{
"error": "Spain locations require country_config with system field (ticketbai, verifactu, or sii)"
}
Invalid system:
{
"error": "system must be \"ticketbai\", \"verifactu\", or \"sii\", got \"invalid\""
}
Territories
| Territory | System | Submission |
|---|---|---|
| Gipuzkoa | TicketBAI | Real-time XML POST |
| Araba | TicketBAI | Real-time XML POST |
| Bizkaia | TicketBAI | LROE batch |