AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Fiz Invoicing

skill-fiz-co-fiz-invoicing-skill-fiz-invoicing · by FIZ-co

>-

No reviews yet
0 installs
16 views
0.0% view→install

Install

$ agentstack add skill-fiz-co-fiz-invoicing-skill-fiz-invoicing

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-fiz-co-fiz-invoicing-skill-fiz-invoicing)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Fiz Invoicing? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

FIZ Invoicing

Issue invoices with the FIZ Public API — a REST gateway at https://api.fiz.co. This skill walks through the full lifecycle: find or create the customer, find or create the items, build a draft invoice, issue it (this is the legally binding step), and optionally download the PDF.

Setup

Every request needs the client's API key in the x-api-key header. Get a key at https://app.fiz.co/settings/integrations.

Store it in an environment variable so it never gets hardcoded into commands:

export FIZ_API_KEY="fiz_api_..."     # the user's key from app.fiz.co
export FIZ_API_URL="https://api.fiz.co"   # optional; this is the default

All examples below use $FIZ_API_KEY and $FIZ_API_URL. If FIZ_API_URL is unset, use https://api.fiz.co. If FIZ_API_KEY is unset, stop and tell the user to set it in their environment (export FIZ_API_KEY=… in their shell, or a secret manager) — do not ask them to paste the key into the chat, and never print or echo the key value. An API key is a credential; keep it out of the conversation transcript.

A reusable curl helper is provided in scripts/fiz.sh. Commands run from the session's working directory (your project root), not the skill directory, so source the helper by its absolute path via ${CLAUDE_SKILL_DIR} (Claude Code sets this to the skill's own directory):

source "${CLAUDE_SKILL_DIR}/scripts/fiz.sh"   # resolves from any working directory
fiz GET /invoices

On a runtime that doesn't provide CLAUDE_SKILL_DIR, substitute that runtime's equivalent skill-directory path (a bare relative scripts/fiz.sh will not resolve from the project root).

The helper prints the HTTP status and returns non-zero on 4xx/5xx, so an error response is never mistaken for success — see "Error handling" below. Plain curl examples are shown inline too; if you use raw curl, always check the HTTP status, not just whether the command exited 0.

The mental model

  • An invoice references a customer (by id) and one or more items (by id).

So customers and items must exist before you can build the invoice.

  • POST /invoices creates a draft. A draft is not yet a legal document — it

is not sent to the tax authority and can be edited or deleted freely.

  • POST /invoices/:id/issue issues it — assigns the official number and

ATCUD, syncs with the Portuguese tax authority (AT), and makes it final. Issuing is not reversible; confirm with the user before issuing. An issued invoice cannot be deleted — the only way to undo it is a credit note.

  • The only exception to "create then issue": if you pass a payment object on

creation for the types INVOICE_RECEIPT or SIMPLIFIED_INVOICE, the document records the payment — but you still issue it to finalize.

Confirmation before writes

These endpoints change state on the user's account. Two levels of care:

  • Plan, then preview all writes before the first one. Once you know what the

request needs, list every write you intend to make for this task — each endpoint plus its JSON payload (the customer to create, each item, the draft invoice) — and show that batch to the user in one preview. Proceed through the writes once they approve the plan. If the plan changes mid-run (e.g. an item lookup fails and you now need to create one), preview the new write before sending it. Never invent customer data, tax fields, or amounts — use only what the user gave you.

  • Before POST /invoices/:id/issue — this is irreversible and reported to the

tax authority. Always get an explicit, separate confirmation (beyond the plan approval above), showing the draft's customer, line items, VAT, and total. Do not issue on your own initiative.

  • Before POST /invoices/credit-notes and POST /invoices/:id/cancel — these

also issue a fiscal change to the AT and are not casually undone. Confirm separately too: for a credit note show which invoice, the reason, and the amount being reversed; for a cancel show which invoice is being voided.

Invocation policy (deliberate): this skill keeps model auto-invocation enabled — the description is the discovery surface, and the real safety net is the preview-all-writes + separate issue confirmation above, not gating discovery. The Codex manifest (agents/openai.yaml) is set to match (allow_implicit_invocation: true). An operator who wants manual-only use can set disable-model-invocation: true in the frontmatter (loads only on /fiz-invoicing).

This is Portuguese tax invoicing — why correctness matters

FIZ issues legally binding fiscal documents that are reported to the Portuguese tax authority (Autoridade Tributária, "AT"). A wrong VAT rate or a missing exemption reason is not a cosmetic bug — it produces an incorrect tax document that, once issued, can only be corrected with a credit note. Get the tax fields right before issuing.

The two things most likely to be wrong, and that you must reason about:

1. VAT rate (vatRate on each item) — never guess it. The rate band (NORMAL | INTERMEDIATE | REDUCED | EXEMPT) and the percentage it maps to depend on the territory (Continental / Açores / Madeira). Default to NORMALREDUCED/INTERMEDIATE apply only to specific legally-defined categories (certain foods, restaurants, cultural events…). If the user hasn't named such a category, use NORMAL and say so, or ask; never silently apply a reduced rate. The per-territory percentage table is in domain.md.

2. VAT exemption requires a reason code (vatExemptionReason). If vatRate is EXEMPT, Portuguese law requires a motivo de isenção — an M-code stating the legal basis. Always set one; an exempt item without a valid reason is an invalid document and can be rejected when you issue. The code must reflect the actual reason: small-business regime → M10, activity exempt by nature (health/education) → M07, EU B2B / reverse charge → M40/M16/M19. If the user is exempt but doesn't know the code, ask why and map it — don't pick arbitrarily. The full code list with legal references is in domain.md.

Other domain rules worth knowing (details in domain.md):

  • CAE is a 5-digit Portuguese economic-activity code that must be one the

business has registered. Don't invent it — ask the user, or reuse the CAE from a previous invoice. It must be a current (Rev. 4) code.

  • NIF (taxpayerNumber) is a 9-digit Portuguese tax number with a checksum;

required for B2B, optional for final consumers. For EU B2B, the customer's VAT number matters for reverse-charge treatment.

  • Withholding tax (retenção na fonte: IRS/IRC/IS) is configured on the item;

common rate is 25% for self-employed services. It is withheld by the payer, reducing the amount actually paid.

  • Document type affects rules: a SIMPLIFIED_INVOICE is for small retail

sales and may omit full customer data; an INVOICE to a business for over €1,000 needs the customer NIF.

Workflow

Follow these steps. Skip 1–2 if the user already gives you a customer id and item ids.

Step 1 — Resolve the customer

Search first to avoid duplicates, then create if needed.

Examples use the fiz helper (see Setup) — it checks the HTTP status for you. The equivalent raw curl is in the appendix.

Find by search term (name, tax number, email):

fiz GET "/customers?search=Joao"

Create a customer (only name is required):

fiz POST /customers '{
  "name": "João Silva",
  "email": "joao.silva@example.com",
  "taxpayerNumber": "303741791",
  "country": "PT"
}'

Keep the returned id — that is the customerId for the invoice.

Step 2 — Resolve the items (products / services)

Find existing items:

fiz GET "/items?search=consulting"

> Reuse an existing item only if its tax fields match the sale. A search hit > with the right name is not enough — for a fiscal document the item's vatRate, > vatTerritory, vatExemptionReason, taxRate and withholding fields must match > the treatment you intend for this customer and sale. If any of them differs > (e.g. same service but the customer is exempt, in another territory, or subject > to withholding), create a new item with the correct fields rather than > reusing the mismatched one. When unsure, inspect the found item's fields and > confirm with the user.

Create an item. Required: name, type (PRODUCT | SERVICE), unitPrice, vatRate (NORMAL | INTERMEDIATE | REDUCED | EXEMPT):

fiz POST /items '{
  "name": "Consulting hour",
  "type": "SERVICE",
  "unitPrice": 80,
  "vatRate": "NORMAL"
}'

Keep each returned id — those are the item ids for the invoice.

> unitPrice is the unit price; per-line totals are computed by FIZ from the > quantity you give in the invoice. Choose vatRate deliberately — see the > domain section above; default to NORMAL unless the category clearly warrants a > reduced rate. If vatRate is EXEMPT, always set a vatExemptionReason M-code > that matches why the sale is exempt (e.g. M10 for the small-business regime). > The field is technically optional at item creation, but an exempt item without a > valid reason is incorrect and can be rejected later when you issue the invoice. > See domain.md for the full code list.

Step 3 — Create the draft invoice

Required fields: dueDate (ISO 8601), cae (Portuguese economic activity code), type, customerId, and items (at least one { id, quantity }).

fiz POST /invoices '{
  "dueDate": "2026-07-18T00:00:00.000Z",
  "cae": "62010",
  "type": "INVOICE",
  "customerId": "6863b1513117c5892ff55296",
  "items": [
    { "id": "68483e978073231c3947077c", "quantity": 10 }
  ]
}'

The response includes the new invoice id (needed to issue) and status (DRAFT). The invoice date is set to now and currency is EUR by the API — you do not send them.

Optional — notes (notes): free-text note shown on the invoice, e.g. "notes": "PO #118".

Optional — series (seriesId): issue this invoice into a specific numbering series instead of the account default. Omit it and the account's default series is used — most accounts only have one, so you rarely need this. When the user does run multiple series (e.g. two brands on one NIF), list them with GET /series and pass the chosen id:

fiz GET /series

Returns the active series, each with id, name, isDefault, status, managementMode, and entries[] (per document type, with the ATCUD validationCode). Pass the id as seriesId on create:

"seriesId": "68483b3fa19e44171e3d0808"

It must be a valid series id from GET /series — there is no silent fallback to the default if it's wrong. A malformed value (not a 24-char Mongo id) is rejected with 400; a well-formed but unknown/wrong-account id is rejected with 404 ("that series does not exist"), not 400.

Optional — global discount (summary):

"summary": { "globalDiscountType": "PERCENT", "globalDiscountPercent": 10 }

Use "AMOUNT" with globalDiscountAmount for a fixed-value discount instead.

Optional — payment on creation (payment): only allowed when type is INVOICE_RECEIPT or SIMPLIFIED_INVOICE; the API returns 400 otherwise.

"payment": { "method": "mbWay", "date": "2026-07-18T00:00:00.000Z" }

method is one of: cash, card, bankTransfer, mbWay, multibanco, spin, other.

Step 3b — Edit the draft (optional)

A draft can be edited before issuing with PATCH /invoices/:id. It uses PATCH semantics — send only the fields you want to change; omitted fields keep their current value. You can update notes, dueDate, cae, customerId, items, summary, payment, and seriesId (e.g. move the draft into another series):

fiz PATCH /invoices/{id} '{ "notes": "PO #118", "seriesId": "68483b3fa19e44171e3d0808" }'

Returns the updated draft. A 404 here means something referenced wasn't found — either the invoice id in the path or a seriesId you passed (a well-formed but unknown series 404s the same way it does on create). Check which before telling the user the draft is gone. Editing is intended for drafts — once an invoice is issued it should be corrected with a credit note, not a PATCH.

Step 4 — Issue the invoice

This is the binding step. Confirm with the user, then:

fiz POST /invoices/{id}/issue

The response has the official number, status: ISSUED, and a syncWithAt block. Check syncWithAt.status — if it is FAILED, the invoice was created locally but did not sync with the tax authority; report atMessage and whether isRetriable is true to the user instead of claiming success.

Step 5 — Download the PDF (optional)

fiz GET /invoices/{id}/pdf

Returns { id, name, url }; the url is a downloadable link to the PDF. Add ?format=A4 or ?format=RECEIPT to choose the layout.

Correcting or cancelling an issued invoice

An issued invoice is a final fiscal document: it cannot be deleted or PATCHed. There are two ways to undo it, both reported to the AT.

Credit note — reverse an issued invoice

A credit note (nota de crédito) reverses a previously issued invoice. Use it to fix a wrong amount, a wrong VAT rate, a document issued by mistake, a return, etc. It is itself a legal document, so it needs a reason code (Anexo 40) and a short reason text.

fiz POST /invoices/credit-notes '{
  "parentInvoiceId": "",
  "reasonCode": "INCORRECT_VAT_RATE",
  "reason": "Correção de IVA — taxa incorreta"
}'
  • parentInvoiceId — the invoice being reversed. The note copies that invoice's

customer and lines, so it reverses the whole document (a full reversal).

  • reasonCode — an Anexo 40 code (see domain.md), e.g. INCORRECT_VAT_RATE,

WRONG_INVOICE, RETURN_GOODS_SERVICES, OPERATION_CANCELLATION. Pick the one that matches why, don't default blindly.

  • reason — a human-readable text. Required — the note is rejected without a

non-empty reason. If you omit it, a default label for the reasonCode is used.

  • issue — optional, defaults to true: the note is created and issued in one

call (it does not stay a draft). Pass "issue": false to leave a draft.

The response is the issued credit note (documentType: CREDIT_NOTE, status: ISSUED, its own number/atcud, a syncWithAt block — check it like any issue). A full credit note also flips the parent invoice to status: CANCELED.

Because a credit note issues immediately and hits the AT, treat it like an issue: confirm with the user first (which invoice, reason, amount).

To fix a wrong invoice and re-bill

The common "I issued it with the wrong VAT / wrong price" fix is two steps:

  1. Credit note the wrong invoice (above) — reverses it.
  2. Issue a new, correct invoice — the normal create + issue flow, with the

right item/VAT this time.

> After re-billing, **verify the VAT on the new document** (GET it back and > check items[].data.vatRate/taxRate), rather than assuming it inherited what > you expected. If you re-bill by reusing a catalog item, confirm that item still > carries the VAT you intend — issuing corrections can leave a catalog item in a > different state than you last saw it.

Cancel — for a document with no credit/debit notes yet

fiz POST /invoices/{id}/cancel

Cancels an issued invoice directly (sets status: CANCELED). This is only allowed while the invoice has no issued credit/debit notes against it — if it does, the API returns 400 and you must work through those notes instead. Prefer a credit note when you need an auditable reversal reason; use cancel for a clean, reason-less voiding of a document nothing else references yet.

Document types (type)

Val

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.