Avvio rapido Portogallo
Questo avvio rapido descrive i passaggi essenziali per iniziare a utilizzare l’API SIGN PT, dall’autenticazione alla creazione del primo documento fiscale. Per una guida più dettagliata, consultate la nostra guida all’integrazione.
Prerequisiti
Sezione intitolata “Prerequisiti”- Un account fiskaly (registratevi su hub.fiskaly.com)
- Una chiave API e un segreto per un’organizzazione
GROUPnell’ambiente TEST - Credenziali dell’utente secondario AT Portal das Finanças per il contribuente (credenziali reali richieste solo in LIVE)
L’API Secret viene mostrato una sola volta. Conservatelo immediatamente in un luogo sicuro.
Passaggi
Sezione intitolata “Passaggi”Autenticarsi
curl -X POST https://test.api.fiskaly.com/tokens \ -H "Content-Type: application/json" \ -H "X-Api-Version: 2026-05-04" \ -d '{ "content": { "type": "API_KEY", "key": "YOUR_API_KEY", "secret": "YOUR_API_SECRET" } }'const BASE = "https://test.api.fiskaly.com"; const API_VERSION = "2026-05-04"; const authResp = await fetch(`${BASE}/tokens`, { method: "POST", headers: { "Content-Type": "application/json", "X-Api-Version": API_VERSION, }, body: JSON.stringify({ content: { type: "API_KEY", key: "YOUR_API_KEY", secret: "YOUR_API_SECRET" }, }), }); const { access_token } = await authResp.json(); const headers = { "Authorization": `Bearer ${access_token}`, "Content-Type": "application/json", "X-Api-Version": API_VERSION, };import requests, uuid BASE = "https://test.api.fiskaly.com" API_VERSION = "2026-05-04" auth = requests.post(f"{BASE}/tokens", json={ "content": {"type": "API_KEY", "key": "YOUR_API_KEY", "secret": "YOUR_API_SECRET"} }, headers={"X-Api-Version": API_VERSION}) access_token = auth.json()["access_token"] hdrs = {"Authorization": f"Bearer {access_token}", "X-Api-Version": API_VERSION}// POST https://test.api.fiskaly.com/tokens // Headers: Content-Type: application/json, X-Api-Version: 2026-05-04 // Body: {"content":{"type":"API_KEY","key":"...","secret":"..."}}using var client = new HttpClient(); client.DefaultRequestHeaders.Add("X-Api-Version", "2026-05-04"); var authResp = await client.PostAsJsonAsync( "https://test.api.fiskaly.com/tokens", new { content = new { type = "API_KEY", key = "YOUR_API_KEY", secret = "YOUR_API_SECRET" } });📘NoteSIGN PT utilizza la stessa piattaforma API unificata di SIGN IT e SIGN FR. Tutte le richieste richiedono l’intestazione
X-Api-Version. Le operazioni di scrittura necessitano anche di un’intestazioneX-Idempotency-Keycon un valore UUIDv3 o UUIDv4.Creare un'Organizzazione
UNITcurl -X POST https://test.api.fiskaly.com/organizations \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -H "X-Api-Version: 2026-05-04" \ -H "X-Idempotency-Key: $(uuidgen)" \ -d '{ "content": { "type": "UNIT", "name": "My Portuguese Merchant" } }'const org = await fetch(`${BASE}/organizations`, { method: "POST", headers: { ...headers, "X-Idempotency-Key": crypto.randomUUID() }, body: JSON.stringify({ content: { type: "UNIT", name: "My Portuguese Merchant" }, }), }).then(r => r.json()); const orgId = org.id;org = requests.post(f"{BASE}/organizations", headers={ **hdrs, "X-Idempotency-Key": str(uuid.uuid4()) }, json={"content": {"type": "UNIT", "name": "My Portuguese Merchant"}}).json() org_id = org["id"]// POST /organizations // Headers: X-Idempotency-Key: <uuid> // Body: {"content":{"type":"UNIT","name":"My Portuguese Merchant"}}client.DefaultRequestHeaders.Add("X-Idempotency-Key", Guid.NewGuid().ToString()); var org = await client.PostAsJsonAsync($"{BASE}/organizations", new { content = new { type = "UNIT", name = "My Portuguese Merchant" } });Creare una chiave API Subject e autenticarsi
Create una chiave API per la
UNIT, quindi autenticatevi con essa:# Create Subject API Key (scoped to the `UNIT`) curl -X POST https://test.api.fiskaly.com/subjects \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -H "X-Api-Version: 2026-05-04" \ -H "X-Idempotency-Key: $(uuidgen)" \ -H "X-Scope-Identifier: ${ORG_ID}" \ -d '{"content": {"type": "API_KEY"}}' # Authenticate with the new API Key curl -X POST https://test.api.fiskaly.com/tokens \ -H "Content-Type: application/json" \ -H "X-Api-Version: 2026-05-04" \ -d '{"content": {"type": "API_KEY", "key": "NEW_KEY", "secret": "NEW_SECRET"}}'// Create Subject API Key scoped to the `UNIT` const subject = await fetch(`${BASE}/subjects`, { method: "POST", headers: { ...headers, "X-Idempotency-Key": crypto.randomUUID(), "X-Scope-Identifier": orgId, }, body: JSON.stringify({ content: { type: "API_KEY" } }), }).then(r => r.json()); // Re-authenticate with the new key const newAuth = await fetch(`${BASE}/tokens`, { method: "POST", headers: { "Content-Type": "application/json", "X-Api-Version": API_VERSION, }, body: JSON.stringify({ content: { type: "API_KEY", key: subject.key, secret: subject.secret }, }), }).then(r => r.json()); headers.Authorization = `Bearer ${newAuth.access_token}`;# Create Subject API Key subject = requests.post(f"{BASE}/subjects", headers={ **hdrs, "X-Idempotency-Key": str(uuid.uuid4()), "X-Scope-Identifier": org_id, }, json={"content": {"type": "API_KEY"}}).json() # Re-authenticate new_auth = requests.post(f"{BASE}/tokens", headers={"X-Api-Version": API_VERSION}, json={"content": {"type": "API_KEY", "key": subject["key"], "secret": subject["secret"]}}).json() hdrs["Authorization"] = f"Bearer {new_auth['access_token']}"// POST /subjects with X-Scope-Identifier: <orgId> // Body: {"content":{"type":"API_KEY"}} // Then POST /tokens with the new key and secret// Create Subject API Key, then re-authenticate with the new credentials // POST /subjects → returns key + secret // POST /tokens → returns new access_tokenCreare Contribuente, Sede e Sistema
⚠️Utente secondario AT Portal das Finanças obbligatorioSIGN PT chiama i servizi web AT per conto del contribuente. Prima di creare un Contribuente in LIVE, il commerciante deve creare un utente secondario dedicato ai servizi web nel Portal das Finanças con le autorizzazioni WSE, WFA e WDT (ove applicabile) e accettare i termini e le condizioni AT. In TEST vengono accettate credenziali segnaposto.
# Create Taxpayer curl -X POST https://test.api.fiskaly.com/taxpayers \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -H "X-Api-Version: 2026-05-04" \ -H "X-Idempotency-Key: $(uuidgen)" \ -d '{ "content": { "type": "COMPANY", "name": { "legal": "Minha Empresa Lda." }, "address": { "line": { "type": "STREET_NUMBER", "street": "Rua Augusta", "number": "28" }, "code": "1100-053", "city": "Lisboa", "country": "PT" }, "fiscalization": { "type": "PT", "tax_id_number": "512345678", "email": "fiscal@minhaempresa.pt", "registration": { "capital": "50000.00", "office": "CRC Lisboa", "other": "sob NIF 512345678" }, "credentials": { "type": "AT", "username": "512345678/3", "password": "YOUR_AT_PASSWORD" } } } }' # Commission Taxpayer curl -X PATCH "https://test.api.fiskaly.com/taxpayers/${TAXPAYER_ID}" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -H "X-Api-Version: 2026-05-04" \ -H "X-Idempotency-Key: $(uuidgen)" \ -d '{"content": {"state": "COMMISSIONED"}}'// Create Taxpayer const taxpayer = await fetch(`${BASE}/taxpayers`, { method: "POST", headers: { ...headers, "X-Idempotency-Key": crypto.randomUUID() }, body: JSON.stringify({ content: { type: "COMPANY", name: { legal: "Minha Empresa Lda." }, address: { line: { type: "STREET_NUMBER", street: "Rua Augusta", number: "28" }, code: "1100-053", city: "Lisboa", country: "PT", }, fiscalization: { type: "PT", tax_id_number: "512345678", email: "fiscal@minhaempresa.pt", registration: { capital: "50000.00", office: "CRC Lisboa", other: "sob NIF 512345678", }, credentials: { type: "AT", username: "512345678/3", password: "YOUR_AT_PASSWORD", }, }, }, }), }).then(r => r.json()); // Commission Taxpayer await fetch(`${BASE}/taxpayers/${taxpayer.id}`, { method: "PATCH", headers: { ...headers, "X-Idempotency-Key": crypto.randomUUID() }, body: JSON.stringify({ content: { state: "COMMISSIONED" } }), }); // Create + Commission Location and System follow the same pattern# Create Taxpayer taxpayer = requests.post(f"{BASE}/taxpayers", headers={ **hdrs, "X-Idempotency-Key": str(uuid.uuid4()) }, json={"content": { "type": "COMPANY", "name": {"legal": "Minha Empresa Lda."}, "address": { "line": {"type": "STREET_NUMBER", "street": "Rua Augusta", "number": "28"}, "code": "1100-053", "city": "Lisboa", "country": "PT", }, "fiscalization": { "type": "PT", "tax_id_number": "512345678", "email": "fiscal@minhaempresa.pt", "registration": { "capital": "50000.00", "office": "CRC Lisboa", "other": "sob NIF 512345678", }, "credentials": { "type": "AT", "username": "512345678/3", "password": "YOUR_AT_PASSWORD", }, }, }}).json() # Commission Taxpayer requests.patch(f"{BASE}/taxpayers/{taxpayer['id']}", headers={ **hdrs, "X-Idempotency-Key": str(uuid.uuid4()) }, json={"content": {"state": "COMMISSIONED"}})// POST /taxpayers // Body: {"content":{"type":"COMPANY","name":{"legal":"Minha Empresa Lda."}, // "address":{"line":{"type":"STREET_NUMBER","street":"Rua Augusta","number":"28"}, // "code":"1100-053","city":"Lisboa","country":"PT"}, // "fiscalization":{"type":"PT","tax_id_number":"512345678", // "email":"fiscal@minhaempresa.pt", // "registration":{"capital":"50000.00","office":"CRC Lisboa","other":"sob NIF 512345678"}, // "credentials":{"type":"AT","username":"512345678/3","password":"YOUR_AT_PASSWORD"}}}} // PATCH /taxpayers/{id} → {"content":{"state":"COMMISSIONED"}} // POST /locations → create BRANCH, then PATCH /locations/{id} → commission // POST /systems → create FISCAL_DEVICE, then PATCH /systems/{id} → commission// POST /taxpayers → create COMPANY with PT fiscalization // fiscalization.type = "PT", tax_id_number = NIF (9 digits) // fiscalization.email = fiscal contact email // fiscalization.registration = { capital, office (CRC), other } // fiscalization.credentials = { type: "AT", username: "<NIF>/<subuser-id>", password } // PATCH /taxpayers/{id} → {"content":{"state":"COMMISSIONED"}} // Same pattern for locations and systems💡Creare prima il ContribuenteDopo aver messo in servizio il Contribuente, create una o più Sedi (
type: "BRANCH") e uno o più Sistemi (type: "FISCAL_DEVICE"). Aggiornate ciascuno aCOMMISSIONEDprima di creare i Record. Consultate la guida all’integrazione completa per la sequenza completa.⚠️Avviso di fatturazioneLa fatturazione inizia non appena un Sistema viene messo in servizio nell’ambiente LIVE — a quel punto inizierà anche a trasmettere documenti ufficiali ad AT.
Nell’ambiente TEST non vengono effettuate fatturazioni né trasmissioni reali.
Creare il primo Record
I Record richiedono due chiamate: una INTENTION seguita da una TRANSACTION.
# Part A: Intention curl -X POST https://test.api.fiskaly.com/records \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -H "X-Api-Version: 2026-05-04" \ -H "X-Idempotency-Key: $(uuidgen)" \ -d '{ "content": { "type": "INTENTION", "system": {"id": "YOUR_SYSTEM_ID"}, "operation": {"type": "TRANSACTION"} } }' # Part B: Transaction curl -X POST https://test.api.fiskaly.com/records \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -H "X-Api-Version: 2026-05-04" \ -H "X-Idempotency-Key: $(uuidgen)" \ -d '{ "content": { "type": "TRANSACTION", "record": {"id": "YOUR_INTENTION_ID"}, "operation": { "type": "RECEIPT", "document": { "number": "FS-2026/00001", "series": "FS-2026", "total_vat": { "amount": "2.30", "exclusive": "10.00", "inclusive": "12.30" } }, "entries": [ { "type": "SALE", "data": { "type": "ITEM", "text": "Product A", "unit": {"quantity": "1.00", "price": "10.00"}, "value": {"base": "10.00"}, "vat": { "type": "VAT_RATE", "code": "STANDARD", "percentage": "23.00", "amount": "2.30", "exclusive": "10.00", "inclusive": "12.30" } }, "details": {"concept": "GOOD"} } ], "payments": [ { "type": "CASH", "details": {"amount": "12.30", "currency": "EUR"} } ] } } }'// Part A: Intention const intention = await fetch(`${BASE}/records`, { method: "POST", headers: { ...headers, "X-Idempotency-Key": crypto.randomUUID() }, body: JSON.stringify({ content: { type: "INTENTION", system: { id: systemId }, operation: { type: "TRANSACTION" }, }, }), }).then(r => r.json()); // Part B: Transaction const record = await fetch(`${BASE}/records`, { method: "POST", headers: { ...headers, "X-Idempotency-Key": crypto.randomUUID() }, body: JSON.stringify({ content: { type: "TRANSACTION", record: { id: intention.id }, operation: { type: "RECEIPT", document: { number: "FS-2026/00001", series: "FS-2026", total_vat: { amount: "2.30", exclusive: "10.00", inclusive: "12.30" }, }, entries: [{ type: "SALE", data: { type: "ITEM", text: "Product A", unit: { quantity: "1.00", price: "10.00" }, value: { base: "10.00" }, vat: { type: "VAT_RATE", code: "STANDARD", percentage: "23.00", amount: "2.30", exclusive: "10.00", inclusive: "12.30", }, }, details: { concept: "GOOD" }, }], payments: [{ type: "CASH", details: { amount: "12.30", currency: "EUR" } }], }, }, }), }).then(r => r.json()); console.log("ATCUD:", record.compliance?.atcud); console.log("QR code:", record.compliance?.qr_code);# Part A: Intention intention = requests.post(f"{BASE}/records", headers={ **hdrs, "X-Idempotency-Key": str(uuid.uuid4()) }, json={"content": { "type": "INTENTION", "system": {"id": system_id}, "operation": {"type": "TRANSACTION"}, }}).json() # Part B: Transaction record = requests.post(f"{BASE}/records", headers={ **hdrs, "X-Idempotency-Key": str(uuid.uuid4()) }, json={"content": { "type": "TRANSACTION", "record": {"id": intention["id"]}, "operation": { "type": "RECEIPT", "document": { "number": "FS-2026/00001", "series": "FS-2026", "total_vat": {"amount": "2.30", "exclusive": "10.00", "inclusive": "12.30"}, }, "entries": [{ "type": "SALE", "data": { "type": "ITEM", "text": "Product A", "unit": {"quantity": "1.00", "price": "10.00"}, "value": {"base": "10.00"}, "vat": { "type": "VAT_RATE", "code": "STANDARD", "percentage": "23.00", "amount": "2.30", "exclusive": "10.00", "inclusive": "12.30", }, }, "details": {"concept": "GOOD"}, }], "payments": [{"type": "CASH", "details": {"amount": "12.30", "currency": "EUR"}}], }, }}).json() print("ATCUD:", record.get("compliance", {}).get("atcud"))// POST /records → INTENTION: system.id, operation.type = "TRANSACTION" // POST /records → TRANSACTION: // record.id = intention ID // operation.type = "RECEIPT" // document: number "FS-2026/00001", series "FS-2026", // total_vat { amount, exclusive, inclusive } // entries[0]: type "SALE", data { type "ITEM", text, unit, value, vat { type "VAT_RATE", code "STANDARD", ... } }, // details { concept "GOOD" } // payments[0]: type "CASH", details { amount, currency "EUR" } // Response includes compliance data: ATCUD, QR code content, hash excerpt, certificate number// POST /records → INTENTION, then POST /records → TRANSACTION // Each requires X-Idempotency-Key header // TRANSACTION body: record.id (intention ID), operation.type "RECEIPT", // document { number, series, total_vat { amount, exclusive, inclusive } }, // entries[0] { type "SALE", data { type "ITEM", text, unit, value, vat { type "VAT_RATE", ... } }, details { concept "GOOD" } }, // payments[0] { type "CASH", details { amount, currency "EUR" } } // Response contains compliance data: ATCUD, QR code, hash excerptUna volta che il Record raggiunge lo stato
COMPLETED, SIGN PT restituisce il payload di conformità per la stampa: codice ATCUD, contenuto del codice QR, estratto hash e numero di certificato del software.
Passaggi successivi
Sezione intitolata “Passaggi successivi”Was this page helpful?