FIZ Rechnungsstellung
Rechnungen mit der FIZ Public API ausstellen — einem REST-Gateway unter https://api.fiz.co.
Dieses Skill führt durch den gesamten Lebenszyklus: Kunden suchen oder anlegen, Artikel suchen oder anlegen, einen Rechnungsentwurf erstellen, ihn ausstellen (dies ist der rechtlich bindende Schritt) und optional das PDF herunterladen.
Einrichtung
Jede Anfrage benötigt den API-Schlüssel des Clients im x-api-key-Header. Erhalten Sie einen Schlüssel unter
https://app.fiz.co/settings/integrations.
Speichern Sie ihn in einer Umgebungsvariable, damit er niemals fest in Befehle codiert wird:
export FIZ_API_KEY="fiz_api_..." # der Schlüssel des Benutzers von app.fiz.co
export FIZ_API_URL="https://api.fiz.co" # optional; dies ist die Standardeinstellung
Alle nachfolgenden Beispiele verwenden $FIZ_API_KEY und $FIZ_API_URL. Wenn FIZ_API_URL nicht gesetzt ist, verwenden Sie https://api.fiz.co. Wenn FIZ_API_KEY nicht gesetzt ist, stoppen Sie und teilen Sie dem Benutzer mit, dass er ihn in seiner Umgebung setzen muss (export FIZ_API_KEY=… in seiner Shell oder einem Secret-Manager) — bitten Sie ihn nicht, den Schlüssel in den Chat einzufügen, und geben Sie den Schlüsselwert niemals aus. Ein API-Schlüssel ist eine Berechtigung; halten Sie ihn aus dem Gesprächsprotokoll heraus.
Ein wiederverwendbarer curl-Helfer wird in scripts/fiz.sh bereitgestellt. Befehle werden aus dem Arbeitsverzeichnis der Sitzung (Ihrem Projektstamm) ausgeführt, nicht aus dem Skill-Verzeichnis. Quellen Sie den Helfer daher über seinen absoluten Pfad mittels ${CLAUDE_SKILL_DIR} (Claude Code setzt dies auf das eigene Verzeichnis des Skills):
source "${CLAUDE_SKILL_DIR}/scripts/fiz.sh" # funktioniert von jedem Arbeitsverzeichnis aus
fiz GET /invoices
Wenn die Laufzeit CLAUDE_SKILL_DIR nicht bereitstellt, ersetzen Sie ihn durch den entsprechenden Skill-Verzeichnispfad dieser Laufzeit (ein bloßes relatives scripts/fiz.sh wird vom Projektstamm aus nicht aufgelöst).
Der Helfer gibt den HTTP-Status aus und gibt bei 4xx/5xx einen Fehlerwert ungleich Null zurück, sodass eine Fehlerantwort niemals fälschlich als Erfolg gewertet wird — siehe „Fehlerbehandlung“ unten. Beispiele mit einfachem curl werden ebenfalls inline gezeigt; wenn Sie rohes curl verwenden, überprüfen Sie immer den HTTP-Status, nicht nur, ob der Befehl mit 0 beendet wurde.
Das mentale Modell
- Eine Rechnung referenziert einen Kunden (per ID) und einen oder mehrere Artikel (per ID). Daher müssen Kunden und Artikel vor der Rechnungserstellung existieren.
POST /invoiceserstellt einen Entwurf. Ein Entwurf ist noch kein rechtliches Dokument – er wird nicht an die Steuerbehörde gesendet und kann frei bearbeitet oder gelöscht werden.POST /invoices/:id/issuestellt die Rechnung aus – vergibt die offizielle Nummer und ATCUD, synchronisiert mit der portugiesischen Steuerbehörde (AT) und macht sie endgültig. Die Ausstellung ist nicht umkehrbar; holen Sie vor der Ausstellung die Zustimmung des Benutzers ein. Eine ausgestellte Rechnung kann nicht gelöscht werden – die einzige Möglichkeit, sie rückgängig zu machen, ist eine Gutschrift.- Die einzige Ausnahme von „Erstellen, dann ausstellen“: Wenn Sie bei der Erstellung für die Typen
INVOICE_RECEIPToderSIMPLIFIED_INVOICEeinpayment-Objekt übergeben, wird die Zahlung im Dokument vermerkt – aber Sie müssen es trotzdem ausstellen, um es abzuschließen.
Bestätigung vor Schreibvorgängen
Diese Endpunkte ändern den Zustand des Benutzerkontos. Zwei Ebenen der Sorgfalt:
- Planen Sie, dann zeigen Sie alle Schreibvorgänge vor dem ersten an. Sobald Sie wissen, was die Anfrage benötigt, listen Sie jeden Schreibvorgang auf, den Sie für diese Aufgabe ausführen möchten – jeden Endpunkt plus sein JSON-Payload (den zu erstellenden Kunden, jeden Artikel, den Rechnungsentwurf) – und zeigen Sie diese Sammlung dem Benutzer in einer einzigen Vorschau an. Fahren Sie mit den Schreibvorgängen fort, sobald sie den Plan genehmigen. Wenn sich der Plan während der Ausführung ändert (z. B. ein Artikelsuchlauf fehlschlägt und Sie jetzt einen erstellen müssen), zeigen Sie den neuen Schreibvorgang vor dem Senden an. Erfinden Sie niemals Kundendaten, Steuerfelder oder Beträge – verwenden Sie nur das, was der Benutzer Ihnen gegeben hat.
- Vor
POST /invoices/:id/issue– dies ist irreversibel und wird der Steuerbehörde gemeldet. Holen Sie immer eine explizite, separate Bestätigung ein (über die oben genannte Planfreigabe hinaus), die den Kunden, die Positionen, die MwSt. und den Gesamtbetrag des Entwurfs zeigt. Stellen Sie nicht eigenmächtig aus.
Aufrufrichtlinie (bewusst): Dieses Skill behält die aktivierte automatische Modellaufrufung bei – die description ist die Erkennungsoberfläche, und das eigentliche Sicherheitsnetz ist die Vorschau aller Schreibvorgänge + separate Ausstellungsbestätigung oben, nicht die Einschränkung der Erkennung. Das Codex-Manifest (agents/openai.yaml) ist entsprechend eingestellt (allow_implicit_invocation: true). Ein Betreiber, der nur manuelle Nutzung wünscht, kann disable-model-invocation: true im Frontmatter setzen (wird nur unter /fiz-invoicing geladen).
Dies ist die portugiesische Steuerrechnung – warum Korrektheit wichtig ist
FIZ stellt rechtlich bindende Steuerdokumente aus, die der portugiesischen Steuerbehörde (Autoridade Tributária, „AT“) gemeldet werden. Ein falscher MwSt.-Satz oder ein fehlender Befreiungsgrund ist kein kosmetischer Fehler – er erzeugt ein falsches Steuerdokument, das nach der Ausstellung nur noch mit einer Gutschrift korrigiert werden kann. Stellen Sie sicher, dass die Steuerfelder vor der Ausstellung korrekt sind.
Die beiden Dinge, die am wahrscheinlichsten falsch sind und über die Sie nachdenken müssen:
1. MwSt.-Satz (vatRate für jeden Artikel) – niemals raten. Die Tarifstufe (NORMAL | INTERMEDIATE | REDUCED | EXEMPT) und der Prozentsatz, auf den sie abbildet, hängen vom Gebiet (Festland / Azoren / Madeira) ab. Standardmäßig NORMAL – REDUCED/INTERMEDIATE gelten nur für bestimmte gesetzlich definierte Kategorien (bestimmte Lebensmittel, Restaurants, kulturelle Veranstaltungen …). Wenn der Benutzer keine solche Kategorie genannt hat, verwenden Sie NORMAL und sagen Sie dies, oder fragen Sie nach; wenden Sie niemals unbemerkt einen ermäßigten Satz an. Die Tabelle der Prozentsätze pro Gebiet finden Sie in domain.md.
2. MwSt.-Befreiung erfordert einen Grundcode (vatExemptionReason).
Wenn vatRate den Wert EXEMPT hat, verlangt das portugiesische Recht einen motivo de isenção – einen M-Code, der die Rechtsgrundlage angibt. Setzen Sie immer einen; ein befreiter Artikel ohne gültigen Grund ist ein ungültiges Dokument und kann bei der Ausstellung abgelehnt werden. Der Code muss den tatsächlichen Grund widerspiegeln: Kleinunternehmerregelung → M10, von Natur aus befreite Tätigkeit (Gesundheit/Bildung) → M07, EU B2B / Reverse Charge → M40/M16/M19. Wenn der Benutzer befreit ist, aber den Code nicht kennt, fragen Sie warum und ordnen Sie ihn zu – wählen Sie nicht willkürlich. Die vollständige Codeliste mit rechtlichen Verweisen finden Sie in domain.md.
Andere relevante Bereichsregeln (Details in domain.md):
- CAE ist eine 5-stellige portugiesische Wirtschaftstätigkeitskennzahl, die das Unternehmen registriert haben muss. Erfinden Sie sie nicht – fragen Sie den Benutzer oder verwenden Sie den CAE einer früheren Rechnung. Es muss ein aktueller Code (Rev. 4) sein.
- NIF (
taxpayerNumber) ist eine 9-stellige portugiesische Steuernummer mit einer Prüfziffer; für B2B erforderlich, für Endverbraucher optional. Bei EU B2B ist die Umsatzsteuer-ID des Kunden für die Reverse-Charge-Behandlung wichtig. - Quellensteuer (retenção na fonte: IRS/IRC/IS) wird auf dem Artikel konfiguriert; üblicher Satz ist 25 % für freiberufliche Dienstleistungen. Sie wird vom Zahlungspflichtigen einbehalten und reduziert den tatsächlich gezahlten Betrag.
- Belegtyp beeinflusst die Regeln: Eine
SIMPLIFIED_INVOICEist für kleine Einzelhandelsverkäufe und kann auf vollständige Kundendaten verzichten; eineINVOICEan ein Unternehmen über 1.000 € benötigt die NIF des Kunden.
Arbeitsablauf
Befolgen Sie diese Schritte. Überspringen Sie die Schritte 1–2, wenn der Benutzer Ihnen bereits eine Kunden-ID und Artikel-IDs gibt.
Schritt 1 – Kunden ermitteln
Suchen Sie zuerst, um Duplikate zu vermeiden, und erstellen Sie dann bei Bedarf.
Beispiele verwenden den fiz-Helfer (siehe Einrichtung) – er prüft den HTTP-Status für Sie. Das entsprechende rohe curl finden Sie im Anhang.
Nach einem Suchbegriff suchen (Name, Steuernummer, E-Mail):
fiz GET "/customers?search=Joao"
Einen Kunden erstellen (nur name ist erforderlich):
fiz POST /customers '{
"name": "João Silva",
"email": "[email protected]",
"taxpayerNumber": "303741791",
"country": "PT"
}'
Behalten Sie die zurückgegebene id – dies ist die customerId für die Rechnung.
Schritt 2 – Artikel ermitteln (Produkte / Dienstleistungen)
Vorhandene Artikel suchen:
fiz GET "/items?search=consulting"
Verwenden Sie einen vorhandenen Artikel nur dann erneut, wenn seine Steuerfelder zum Verkauf passen. Ein Suchergebnis mit dem richtigen Namen reicht nicht – für ein Steuerdokument müssen die Felder
vatRate,vatTerritory,vatExemptionReason,taxRateund die Quellensteuerfelder des Artikels mit der Behandlung übereinstimmen, die Sie für diesen Kunden und Verkauf beabsichtigen. Wenn eines davon abweicht (z. B. gleiche Dienstleistung, aber der Kunde ist befreit, in einem anderen Gebiet oder unterliegt der Quellensteuer), erstellen Sie einen neuen Artikel mit den korrekten Feldern, anstatt den nicht passenden wiederzuverwenden. Wenn Sie sich unsicher sind, prüfen Sie die Felder des gefundenen Artikels und bestätigen Sie mit dem Benutzer.
Einen Artikel erstellen. Erforderlich: name, type (PRODUCT | SERVICE), unitPrice, vatRate (NORMAL | INTERMEDIATE | REDUCED | EXEMPT):
fiz POST /items '{
"name": "Beratungsstunde",
"type": "SERVICE",
"unitPrice": 80,
"vatRate": "NORMAL"
}'
Behalten Sie jede zurückgegebene id – dies sind die Artikel-IDs für die Rechnung.
unitPriceist der Einzelpreis; die Gesamtsummen pro Zeile werden von FIZ aus derquantityberechnet, die Sie in der Rechnung angeben. Wählen SievatRatebewusst – siehe den Bereichsabschnitt oben; standardmäßigNORMAL, es sei denn, die Kategorie rechtfertigt eindeutig einen ermäßigten Satz. WennvatRateden WertEXEMPThat, setzen Sie immer einenvatExemptionReasonM-Code, der warum der Verkauf befreit ist (z. B.M10für die Kleinunternehmerregelung). Das Feld ist technisch gesehen optional bei der Artikelerstellung, aber ein befreiter Artikel ohne gültigen Grund ist falsch und kann später bei der Rechnungsausstellung abgelehnt werden. Siehedomain.mdfür die vollständige Codeliste.
Schritt 3 – Den Rechnungsentwurf erstellen
Erforderliche Felder: dueDate (ISO 8601), cae (portugiesische Wirtschaftstätigkeitskennzahl), type, customerId und items (mindestens ein { id, quantity }).
fiz POST /invoices '{
"dueDate": "2026-07-18T00:00:00.000Z",
"cae": "62010",
"type": "INVOICE",
"customerId": "6863b1513117c5892ff55296",
"items": [
{ "id": "68483e978073231c3947077c", "quantity": 10 }
]
}'
Die Antwort enthält die neue Rechnungs-id (benötigt zum Ausstellen) und den status (DRAFT). Das Rechnungsdatum (date) wird auf jetzt gesetzt und die currency ist standardmäßig EUR von der API – Sie senden diese nicht.
Optional – globaler Rabatt (summary):
"summary": { "globalDiscountType": "PERCENT", "globalDiscountPercent": 10 }
Verwenden Sie stattdessen "AMOUNT" mit globalDiscountAmount für einen festen Rabattbetrag.
Optional – Zahlung bei Erstellung (payment): nur zulässig, wenn type INVOICE_RECEIPT oder SIMPLIFIED_INVOICE ist; andernfalls gibt die API 400 zurück.
"payment": { "method": "mbWay", "date": "2026-07-18T00:00:00.000Z" }
method ist einer von: cash, card, bankTransfer, mbWay, multibanco, spin, other.
Schritt 4 – Die Rechnung ausstellen
Dies ist der bindende Schritt. Bestätigen Sie mit dem Benutzer, dann:
fiz POST /invoices/{id}/issue
Die Antwort enthält die offizielle number, den status: ISSUED und einen syncWithAt-Block. Überprüfen Sie syncWithAt.status – wenn es FAILED ist, wurde die Rechnung lokal erstellt, aber nicht mit der Steuerbehörde synchronisiert; melden Sie atMessage und ob isRetriable wahr ist, an den Benutzer, anstatt Erfolg zu behaupten.
Schritt 5 – PDF herunterladen (optional)
fiz GET /invoices/{id}/pdf
Gibt { id, name, url } zurück; die url ist ein herunterladbarer Link zum PDF. Fügen Sie ?format=A4 oder ?format=RECEIPT hinzu, um das Layout auszuwählen.
Belegtypen (type)
Werte: INVOICE · INVOICE_RECEIPT · SIMPLIFIED_INVOICE · RECEIPT · CREDIT_NOTE · DEBIT_NOTE. Standardmäßig INVOICE, es sei denn, der Benutzer fragt nach einer Quittung oder einer vereinfachten Rechnung. Nur INVOICE_RECEIPT und SIMPLIFIED_INVOICE akzeptieren ein payment-Objekt bei der Erstellung. Siehe domain.md für die Bedeutung der einzelnen Typen und deren Verwendung.
Allgemeine Operationsreferenz
| Aktion | Methode & Pfad |
|---|---|
| Kunden suchen/auflisten | GET /customers?search=… |
| Kunden erstellen | POST /customers |
| Artikel suchen/auflisten | GET /items?search=… |
| Artikel erstellen | POST /items |
| Entwurf erstellen | POST /invoices |
| Ausstellen | POST /invoices/:id/issue |
| Rechnungen auflisten | GET /invoices |
| Eine Rechnung abrufen | GET /invoices/:id |
| PDF herunterladen | GET /invoices/:id/pdf |
| Löschen (Entwurf) | DELETE /invoices/:id |
Fehlerbehandlung
Überprüfen Sie immer den HTTP-Status, nicht nur, ob der Befehl ausgeführt wurde. Im Fehlerfall gibt die API einen normal aussehenden JSON-Body zurück – { "statusCode": 400, "message": "...", "timestamp": "..." } – mit dem passenden HTTP-Status. Bei rohem curl -s wird dieser Body ausgegeben und curl beendet sich trotzdem mit 0, sodass leicht ein Fehler mit einem Ergebnis verwechselt werden kann. Der fiz-Helfer schützt davor: Er gibt eine HTTP <code>-Zeile aus und gibt bei 4xx/5xx einen Fehlerwert ungleich Null zurück. Wenn Sie rohes curl verwenden müssen, fügen Sie -w '\n%{http_code}' (oder -o body -w '%{http_code}') hinzu und überprüfen Sie den Code.
Häufige Statuscodes:
- 401 – fehlender/ungültiger API-Schlüssel. Sagen Sie dem Benutzer, er solle
FIZ_API_KEYin seiner Umgebung setzen (nicht im Chat). - 400 – Validierungsfehler; die
messagegibt an, welches Feld. Typische Fälle: leereitems,paymentbei einem nicht unterstütztentype, ein unbekanntes/zusätzliches Feld (strenge Whitelist), fehlerhaftesdueDate(muss vollständiges ISO 8601 mit Zeitzone sein, z. B.2026-07-18T00:00:00.000Z). - 5xx – Backend-/AT-Problem; zeigen Sie es an, wiederholen Sie nicht blind denselben Schreibvorgang (ein create könnte teilweise erfolgreich gewesen sein – überprüfen Sie zuerst mit einem
GET).
Geben Sie die message der API immer an den Benutzer weiter, anstatt blind zu wiederholen.
Der vollständige, maßgebliche Anfrage-/Antwortvertrag ist die Live-Swagger-UI unter https://api.fiz.co/ – konsultieren Sie diese, wenn ein Feld hier veraltet erscheint.
Wenn Sie mehr Details benötigen
Zwei Begleitdateien in diesem Skill-Verzeichnis:
domain.md– die portugiesische Steuerdomäne: MwSt.-Sätze pro Gebiet, die vollständige Liste der Befreiungs- (M) Codes und wann jeder anzuwenden ist, Belegtypen, CAE/NIF-Regeln, Quellensteuer und wie die AT-Synchronisation / Unumkehrbarkeit der Ausstellung funktionieren. Lesen Sie es immer dann, wenn eine Steuerentscheidung nicht offensichtlich ist (insbesondere bei der Wahl einesvatRateoder eines Befreiungsgrundes).reference.md– die vollständige feldbezogene API-Referenz (jedes Kunden-/Artikel-/Rechnungsfeld, alle Enum-Werte, vollständige Anfrage-/Antwortformen).
Anhang – rohes curl (ohne den Helfer)
Bevorzugen Sie den fiz-Helfer oben; er prüft den HTTP-Status. Wenn er nicht verfügbar ist, verwenden Sie rohes curl mit -w '\n...