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:
- You create a transaction via
POST /v1/transactions - FiscalAPI assigns a gap-free sequential number for the document series
- An ATCUD code is generated using the AT-assigned validation code and sequence number
- A QR code content string is built per Portaria 195/2020 specification
- A 4-character document hash is computed (SHA-256)
- Your transaction completes immediately with a
fiscal_id, ATCUD, and QR content - 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:
| Field | ID | Description | Example |
|---|---|---|---|
| Issuer NIF | A | Seller tax number | 123456789 |
| Buyer NIF | B | Buyer tax number (999999990 for final consumers) | 999999990 |
| Buyer country | C | Buyer country code | PT |
| Document type | D | FT, FS, FR, NC, ND | FT |
| Document status | E | N (normal), A (cancelled) | N |
| Document date | F | YYYYMMDD | 20260315 |
| Document ID | G | Series/number | FT A/1 |
| ATCUD | H | Full ATCUD code | ABCD1234-1 |
| Tax breakdown | I1-I8 | Country, base amounts, tax amounts by rate | |
| Tax total | N | Total tax | 23.00 |
| Gross total | O | Total with tax | 123.00 |
| Hash | Q | First 4 chars of document hash | a1b2 |
| Certificate | R | Software certificate number | 1234 |
FiscalAPI generates the QR content string automatically and returns it in the qr_code_url field of the transaction response.
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
| Type | Code | Description |
|---|---|---|
| Standard invoice | FT | Fatura -- full tax invoice |
| Simplified invoice | FS | Fatura Simplificada -- for sales under €100 to final consumers |
| Invoice-receipt | FR | Fatura-Recibo -- invoice with payment receipt |
| Credit note | NC | Nota de Crédito -- reversal/credit |
| Debit note | ND | Nota 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 tier | Mainland | Azores (PT-AC) | Madeira (PT-MA) |
|---|---|---|---|
| Reduced | 6% | 4% | 5% |
| Intermediate | 13% | 9% | 12% |
| Normal | 23% | 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:
| Field | Type | Required | Description |
|---|---|---|---|
series_type | string | Yes | Document 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_idfield, not incountry_config. |atcud_validation_code| string | Yes | AT-assigned validation code for the document series (8+ alphanumeric characters) |
Validation rules
| Field | Rule | Example |
|---|---|---|
tax_id (NIF) | 9 digits, mod-11 check digit, cannot start with 0 or 4 (set on location, not in country_config) | 501442600 |
series_type | Must be one of: FT, FS, FR, NC, ND | FT |
atcud_validation_code | Non-empty alphanumeric string from AT | ABCD1234 |
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
}
]
}'