Portugal Schnellstart
Dieser Schnellstart beschreibt die wesentlichen Schritte für den Einstieg in die SIGN PT API, von der Authentifizierung bis zur Erstellung Ihres ersten Steuerbelegs. Eine ausführlichere Anleitung finden Sie in unserem Integrationshandbuch.
Voraussetzungen
Abschnitt betitelt „Voraussetzungen“- Ein fiskaly-Konto (Registrierung unter hub.fiskaly.com)
- Ein API-Key und Secret für eine Organisation
GROUPin der TEST-Umgebung - AT Portal das Finanças Unterbenutzer-Zugangsdaten für den Steuerpflichtigen (echte Zugangsdaten nur in LIVE erforderlich)
Ihr API-Secret wird nur einmal angezeigt. Speichern Sie es sofort an einem sicheren Ort.
Schritte
Abschnitt betitelt „Schritte“Authentifizieren
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 verwendet dieselbe Unified API-Plattform wie SIGN IT und SIGN FR. Alle Anfragen erfordern den Header
X-Api-Version. Schreiboperationen benötigen zusätzlich einenX-Idempotency-Key-Header mit einem UUIDv3- oder UUIDv4-Wert.Organisation
UNITerstellencurl -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" } });Subject-API-Key erstellen und authentifizieren
Erstellen Sie einen API-Key für die
UNITund authentifizieren Sie sich damit:# 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_tokenSteuerpflichtigen, Standort und System erstellen
⚠️AT Portal das Finanças Unterbenutzer erforderlichSIGN PT ruft AT-Webservices im Auftrag des Steuerpflichtigen auf. Bevor ein Steuerpflichtiger in LIVE angelegt wird, muss der Händler im Portal das Finanças einen dedizierten Webservice-Unterbenutzer mit den Berechtigungen WSE, WFA und WDT (sofern zutreffend) erstellen und die AT-Nutzungsbedingungen akzeptieren. In TEST werden Platzhalter-Zugangsdaten akzeptiert.
# 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💡Zuerst Steuerpflichtigen erstellenErstellen Sie nach der Inbetriebnahme des Steuerpflichtigen einen oder mehrere Standorte (
type: "BRANCH") und ein oder mehrere Systeme (type: "FISCAL_DEVICE"). Aktualisieren Sie jeden Eintrag aufCOMMISSIONED, bevor Sie Records erstellen. Die vollständige Abfolge finden Sie im vollständigen Integrationshandbuch.⚠️Hinweis zur AbrechnungDie Abrechnung beginnt, sobald ein System in der LIVE-Umgebung in Betrieb genommen wird — zu diesem Zeitpunkt beginnt es auch mit der Übermittlung offizieller Dokumente an AT.
In der TEST-Umgebung finden keine Abrechnungen oder echten Übertragungen statt.
Ersten Beleg erstellen
Records erfordern zwei Aufrufe: eine INTENTION, gefolgt von einer 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 excerptSobald der Record den Status
COMPLETEDerreicht, gibt SIGN PT die Compliance-Nutzlast für den Druck zurück: ATCUD-Code, QR-Code-Inhalt, Hash-Auszug und die Softwarezertifikatsnummer.
Nächste Schritte
Abschnitt betitelt „Nächste Schritte“Was this page helpful?