Démarrage rapide Portugal
Ce guide de démarrage rapide couvre les étapes essentielles pour commencer avec l’API SIGN PT, de l’authentification à la création de votre premier enregistrement fiscal. Pour une présentation plus détaillée, consultez notre guide d’intégration.
Prérequis
Section intitulée « Prérequis »- Un compte fiskaly (inscrivez-vous sur hub.fiskaly.com)
- Une clé API et un secret pour une Organisation
GROUPdans l’environnement TEST - Identifiants de sous-utilisateur AT Portal das Finanças pour le contribuable (identifiants réels requis uniquement en LIVE)
Votre API Secret n’est affiché qu’une seule fois. Stockez-le immédiatement dans un endroit sûr.
S'authentifier
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 utilise la même plateforme d’API unifiée que SIGN IT et SIGN FR. Toutes les requêtes nécessitent l’en-tête
X-Api-Version. Les opérations d’écriture nécessitent également un en-têteX-Idempotency-Keyavec une valeur UUIDv3 ou UUIDv4.Créer une Organisation
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" } });Créer une clé API Subject et s'authentifier
Créez une clé API pour la
UNIT, puis authentifiez-vous avec celle-ci :# 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_tokenCréer un Contribuable, un Site et un Système
⚠️Sous-utilisateur AT Portal das Finanças requisSIGN PT appelle les services web AT au nom du contribuable. Avant de créer un Contribuable en LIVE, le marchand doit créer un sous-utilisateur de service web dédié dans le Portal das Finanças avec les permissions WSE, WFA et WDT (le cas échéant) et accepter les conditions générales AT. En TEST, des identifiants fictifs sont acceptés.
# 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💡Créer le Contribuable en premierAprès la mise en service du Contribuable, créez un ou plusieurs Sites (
type: "BRANCH") et un ou plusieurs Systèmes (type: "FISCAL_DEVICE"). Mettez à jour chacun àCOMMISSIONEDavant de créer des Enregistrements. Consultez le guide d’intégration complet pour la séquence complète.⚠️Avertissement de facturationLa facturation commence dès qu’un Système est mis en service dans l’environnement LIVE — à ce moment, il commence également à transmettre des documents officiels à AT.
Aucune facturation ni transmission réelle n’a lieu dans l’environnement TEST.
Créer votre premier Enregistrement
Les Enregistrements nécessitent deux appels : une INTENTION suivie d’une 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 excerptUne fois que l’Enregistrement atteint l’état
COMPLETED, SIGN PT renvoie le payload de conformité pour l’impression : le code ATCUD, le contenu du code QR, l’extrait de hachage et le numéro de certificat logiciel.
Prochaines étapes
Section intitulée « Prochaines étapes »Was this page helpful?