Skip to main content

Portugal Fiscalization Guide

Portugal requires all invoicing software to generate ATCUD codes (unique document identifiers) and QR codes on every invoice, and to submit SAF-T PT billing files to the Autoridade Tributária (AT) monthly. Unlike Spain and Italy, there is no real-time government API call per transaction -- compliance is enforced through local document generation and monthly batch submission.

FiscalAPI handles ATCUD generation, QR code content, document sequencing, and SAF-T file preparation automatically.

How it works

Portugal's flow is synchronous and local per transaction, with monthly batch submission:

  1. You create a transaction via POST /v1/transactions
  2. FiscalAPI assigns a gap-free sequential number for the document series
  3. An ATCUD code is generated using the AT-assigned validation code and sequence number
  4. A QR code content string is built per Portaria 195/2020 specification
  5. A 4-character document hash is computed (SHA-256)
  6. Your transaction completes immediately with a fiscal_id, ATCUD, and QR content
  7. At month end, FiscalAPI generates and submits the SAF-T PT billing file to AT

There is no per-transaction government API call -- transactions complete in ~10ms.

ATCUD codes

Every Portuguese invoice must carry an ATCUD (Código Único de Documento). The ATCUD uniquely identifies each document and is composed of two parts:

ATCUD: {ValidationCode}-{SequentialNumber}
  • ValidationCode: An alphanumeric code (8+ characters) obtained from AT when registering a document series
  • SequentialNumber: A gap-free sequential number within the series

Example: ABCD1234-42 (validation code ABCD1234, document number 42)

Series registration

Before issuing documents, each series must be registered with AT to obtain a validation code. FiscalAPI manages series registration and stores the assigned validation codes. You provide the validation code in your location's country_config.

QR code

Every invoice must include a QR code containing structured data per Portaria 195/2020. The QR content is a text string with fields separated by *, each prefixed with its identifier:

FieldIDDescriptionExample
Issuer NIFASeller tax number123456789
Buyer NIFBBuyer tax number (999999990 for final consumers)999999990
Buyer countryCBuyer country codePT
Document typeDFT, FS, FR, NC, NDFT
Document statusEN (normal), A (cancelled)N
Document dateFYYYYMMDD20260315
Document IDGSeries/numberFT A/1
ATCUDHFull ATCUD codeABCD1234-1
Tax breakdownI1-I8Country, base amounts, tax amounts by rate
Tax totalNTotal tax23.00
Gross totalOTotal with tax123.00
HashQFirst 4 chars of document hasha1b2
CertificateRSoftware certificate number1234

FiscalAPI generates the QR content string automatically and returns it in the qr_code_url field of the transaction response.

tip

The qr_code_url field contains the QR code content string, not an image URL. Use any QR code library to render the string as a scannable QR image on your receipts.

Document types

TypeCodeDescription
Standard invoiceFTFatura -- full tax invoice
Simplified invoiceFSFatura Simplificada -- for sales under €100 to final consumers
Invoice-receiptFRFatura-Recibo -- invoice with payment receipt
Credit noteNCNota de Crédito -- reversal/credit
Debit noteNDNota de Débito -- debit adjustment

FiscalAPI maps transaction types to document codes:

  • sale → FT (or FS for simplified invoices)
  • void → status A (Anulado / cancelled)
  • Credit notes → NC

VAT rates

Portugal has three standard VAT rate tiers, with reduced rates for the Azores and Madeira:

Rate tierMainlandAzores (PT-AC)Madeira (PT-MA)
Reduced6%4%5%
Intermediate13%9%12%
Normal23%16%22%

FiscalAPI automatically groups line items by rate tier for the QR code tax breakdown and SAF-T generation.

SAF-T PT monthly submission

Portugal requires monthly submission of SAF-T PT billing files (v1.04_01) to the AT. The SAF-T file is an XML document containing:

  • Header: Company identification, fiscal year, software certification
  • Master files: Customers, products, tax table
  • Source documents: All invoices issued in the period with full detail

FiscalAPI generates the SAF-T file from your transactions and submits it to AT via their web service. You can also trigger manual SAF-T generation via the batch endpoint.

Country config fields

The country_config object for Portuguese locations:

FieldTypeRequiredDescription
series_typestringYesDocument type code: FT, FS, FR, NC, or ND

Note: The Portuguese NIF (9-digit tax number with mod-11 check digit) is provided via the location's tax_id field, not in country_config. | atcud_validation_code | string | Yes | AT-assigned validation code for the document series (8+ alphanumeric characters) |

Validation rules

FieldRuleExample
tax_id (NIF)9 digits, mod-11 check digit, cannot start with 0 or 4 (set on location, not in country_config)501442600
series_typeMust be one of: FT, FS, FR, NC, NDFT
atcud_validation_codeNon-empty alphanumeric string from ATABCD1234
NIF validation

Portuguese NIFs use a weighted mod-11 checksum. The last digit is the check digit, calculated from the first 8 digits with weights 9, 8, 7, 6, 5, 4, 3, 2. Valid first digits: 1-3 (individual), 5 (company), 6 (public), 7 (other entity), 8 (sole trader), 9 (irregular/temporary).

Configuration example

curl -X POST https://api.fiscalapi.com/v1/locations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer fsk_test_abc123def456..." \
-d '{
"name": "Lisbon Store",
"country": "PT",
"address": "Rua Augusta 100, 1100-053 Lisboa",
"tax_id": "501442600",
"country_config": {
"series_type": "FT",
"atcud_validation_code": "ABCD1234"
}
}'

Creating a transaction

curl -X POST https://api.fiscalapi.com/v1/transactions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer fsk_test_abc123def456..." \
-d '{
"location_id": "loc_abc123",
"type": "sale",
"amount": 12300,
"currency": "EUR",
"line_items": [
{
"description": "Pastel de nata",
"quantity": 6,
"unit_price": 150,
"vat_rate": 600
},
{
"description": "Vinho verde",
"quantity": 1,
"unit_price": 1200,
"vat_rate": 2300
}
]
}'

Specifying a buyer

For B2B transactions, include the buyer's NIF and country in the transaction metadata:

{
"metadata": {
"buyer_nif": "500100144",
"buyer_country": "PT"
}
}

If omitted, the buyer defaults to a final consumer (NIF 999999990, country PT).

Response

{
"id": "txn_abc123",
"status": "success",
"fiscal_id": "PT-A 2026/-1",
"qr_code_url": "A:501442600*B:999999990*C:PT*D:FT*E:N*F:20260315*G:FT A 2026//1*H:ABCD1234-1*I1:PT*I3:7.36*I4:0.54*I5:9.76*I6:2.76*N:3.30*O:123.00*Q:a1b2",
"created_at": "2026-03-15T10:30:00Z"
}

The qr_code_url contains the full QR content string. The fiscal_id format is PT-{Series}-{SequenceNumber}.

Error examples

Missing NIF:

{
"error": "nif is required"
}

Invalid NIF (mod-11 check digit failure):

{
"error": "nif is invalid: \"123456780\""
}

Missing series type:

{
"error": "Portugal country_config.series_type is required"
}

Missing ATCUD validation code:

{
"error": "Portugal country_config.atcud_validation_code is required"
}

Sandbox testing

Use test_mode: true on your transactions to test Portugal fiscalization without affecting production series sequences. Sandbox transactions use separate ATCUD sequences and are excluded from SAF-T submissions.

curl -X POST https://api.fiscalapi.com/v1/transactions \
-H "Authorization: Bearer fsk_test_abc123def456..." \
-d '{
"location_id": "loc_abc123",
"type": "sale",
"test_mode": true,
"amount": 1500,
"currency": "EUR",
"line_items": [
{
"description": "Test item",
"quantity": 1,
"unit_price": 1220,
"vat_rate": 2300
}
]
}'