FIZ / developers

Getting started

Quickstart: your first invoice from code

Five requests take you from an API key to a draft invoice you can open as a PDF, with your own code or with a coding agent. Nothing reaches the tax authority until the last, optional step.

1. Get an API key

Sign in to FIZ and open Settings → Integrations. Create an API key: it belongs to one company and can only issue for that company. Copy it once; FIZ stores only a hash.

Put it in the environment as FIZ_API_KEY and load it into the shell before running anything. Every snippet below, and the FIZ skill for coding agents, reads that variable, so you never paste the key into a chat, a prompt or a repository. A new terminal needs the load step again.

# .env (never commit it; add it to .gitignore)
FIZ_API_KEY=fiz_api_...
# A shell does not read .env by itself. Run this in the terminal you use for
# the snippets; a coding agent started from that terminal inherits the key.
set -a; source .env; set +a

2. Check the connection

The first request tells you whether the key works and whether the company can issue.

curl https://api.fiz.co/company \
  --header "x-api-key: $FIZ_API_KEY"

The response carries id, name, taxpayerNumber, cae and readiness. If readiness.ready is false, reasons[].code says what is missing (AT_CREDENTIALS_REQUIRED, AT_SYNC_REQUIRED, SERIES_REQUIRED) and actionUrl is the page in FIZ that fixes it. You can still create drafts while not ready.

A 401 means the key is missing or revoked. Note the cae value: a draft needs one of the company's activity codes.

3. Create a customer and an item

An invoice references a customer and one or more catalogue items by id. Create one of each and keep the returned id values. The Idempotency-Key header makes a retry safe: the same key returns the first response instead of creating a second record.

curl --request POST https://api.fiz.co/customers \
  --header "x-api-key: $FIZ_API_KEY" \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: quickstart-customer-1' \
  --data '{"name":"Example customer","country":"PT"}'
curl --request POST https://api.fiz.co/items \
  --header "x-api-key: $FIZ_API_KEY" \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: quickstart-item-1' \
  --data '{"name":"Example service","type":"SERVICE","unitPrice":10,"vatRate":"NORMAL"}'

Send only documented fields: validation is strict and an unknown field is a 400. vatRate and any exemption code are a tax decision for the company; the example category is not tax advice.

4. Create a draft and look at it

Save this as draft.json, replacing the two ids with the ones you just received and cae with a value from your company response. The item reference is items[].id.

{
  "type": "INVOICE",
  "cae": "62010",
  "customerId": "aaaaaaaaaaaaaaaaaaaaaaaa",
  "items": [
    {
      "id": "bbbbbbbbbbbbbbbbbbbbbbbb",
      "quantity": 1
    }
  ]
}
curl --request POST https://api.fiz.co/invoices \
  --header "x-api-key: $FIZ_API_KEY" \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: quickstart-draft-1' \
  --data @draft.json

The response is the draft, with its id, status and updatedAt. Read it back and check totals, VAT and the customer block in the PDF before anything fiscal happens. The PDF endpoint returns a download link, not the file: fetch url from its response.

curl https://api.fiz.co/invoices/$INVOICE_ID \
  --header "x-api-key: $FIZ_API_KEY"

# The PDF endpoint answers { id, name, url }: download the url (jq extracts it).
PDF_URL=$(curl -s https://api.fiz.co/invoices/$INVOICE_ID/pdf \
  --header "x-api-key: $FIZ_API_KEY" | jq -r .url)
curl -L "$PDF_URL" --output draft.pdf

A draft can be changed with PATCH /invoices/{id} and removed with DELETE /invoices/{id}. Create as many as you need.

5. Issue (fiscal, irreversible)

Issuing assigns the number and ATCUD and reports the document to the AT. It cannot be undone; a mistake is corrected with a credit note. Do the first one by hand, after reading the PDF, and only when readiness.ready is true.

# Once per issue attempt. Store it next to the invoice id; a retry must reuse it.
ISSUE_KEY=$(uuidgen)
# Fiscal and irreversible. expectedUpdatedAt is the draft's updatedAt from GET /invoices/{id}.
# Safe to re-run after a lost response: the same ISSUE_KEY returns the recorded result.
curl --request POST https://api.fiz.co/invoices/$INVOICE_ID/issue \
  --header "x-api-key: $FIZ_API_KEY" \
  --header 'Content-Type: application/json' \
  --header "Idempotency-Key: $ISSUE_KEY" \
  --data '{ "expectedUpdatedAt": "2026-09-15T10:20:30.000Z" }'

Send the draft's current updatedAt as expectedUpdatedAt: if the draft changed in between, the request is refused instead of issuing a stale version. Generate the Idempotency-Key once per issue and store it next to the invoice id; after a lost response, retry with that same key and the server returns the recorded result instead of issuing twice. A new key is a new attempt.

6. Build it with a coding agent

Give your agent this prompt. It points it at the Markdown docs written for agents, fixes the key convention and keeps fiscal actions behind your explicit request.

I'm integrating FIZ, a certified invoicing API for Portugal (https://api.fiz.co).
Read https://api.fiz.co/llms.txt first and follow its links before writing any code.
My API key is in the FIZ_API_KEY environment variable. Never print it, log it or ask me to paste it.
Start with GET https://api.fiz.co/company to verify the key and the company's readiness.
Drafts are safe to create, change and delete. Do not call /issue, /pay, /cancel or credit-note endpoints unless I explicitly ask: they are fiscal and irreversible.
Task: <describe what to build>

For a project that keeps evolving, add one line to CLAUDE.md, AGENTS.md or .cursorrules so every session starts from the right place:

FIZ invoicing API: read https://api.fiz.co/llms.txt before touching the integration.
The API key is in FIZ_API_KEY; never print it. Drafts are safe; never call /issue, /pay, /cancel or credit notes unless asked.

Other ways in

Claude Code: connect the FIZ MCP server and your assistant reads and drafts documents itself, with OAuth instead of a key. Details on the MCP page.

claude mcp add --transport http fiz https://api.fiz.co/mcp
  • Skill: the open-source fiz-invoicing skill adds Portuguese VAT rules and a curl helper to Claude Code and other Agent Skills runtimes.
  • Docs for agents: llms.txt indexes Markdown editions of every page here; the OpenAPI document is at /-json.
  • Building for your customers? That is an OAuth app, not an API key: follow Build an app with FIZ.