Guia de integrações
Crie uma aplicação com o FIZ
Ligue as empresas dos seus clientes, crie rascunhos de faturas e integre faturação certificada no seu produto. Comece com um exemplo funcional e reproduza o mesmo fluxo no seu servidor.
1. Execute o exemplo
O exemplo é a sua aplicação parceira: um ecrã de encomendas com cliente, serviço e ação de faturação. O FIZ aparece como fornecedor de faturação. Defina APP_NAME com o nome do seu produto, igual ao nome registado no FIZ.
localhost:3100 executa esta aplicação parceira no seu computador. A entrada e o registo acontecem em app.fiz.co; OAuth e os pedidos REST usam api.fiz.co. A aplicação liga-se diretamente ao FIZ de produção.
Precisa de Node.js 22.17 ou superior, Git e uma aplicação Development registada. Não há dependências de pacotes nem chave API.
git clone https://github.com/FIZ-co/partner-app-demo.git
cd partner-app-demo
cp .env.example .env
# Fill in APP_NAME and the three FIZ credentials, then:
npm start
# Open http://localhost:3100Use o mesmo nome de aplicação que no FIZ e preencha o ID da aplicação, client ID e segredo no .env do servidor:
APP_NAME="Your product name"
FIZ_APP_ID=YOUR_APPLICATION_ID
FIZ_CLIENT_ID=YOUR_CLIENT_ID
FIZ_CLIENT_SECRET=YOUR_CLIENT_SECRETAbra a encomenda e escolha Connect FIZ ou Create a FIZ account. Após o consentimento, regressa à mesma encomenda com a empresa ligada. Escolha o CAE e a categoria de IVA e clique em Create invoice draft. A encomenda passa a mostrar o ID do rascunho guardado no FIZ.
Sem credenciais, Set up FIZ mostra instruções e o callback correto para a sua porta. Nunca é iniciada uma ligação FIZ fictícia. Guarde o segredo apenas no servidor.
2. Registe a aplicação
Entre no FIZ e abra Definições → Integrações → Aplicações de programador. Se o FIZ pedir que conclua a configuração da conta/empresa, termine-a para abrir Definições. Criar uma aplicação não exige um plano pago. Escolha Development para a primeira aplicação.
| Definição | Valor para o exemplo local |
|---|---|
| Nome / nome do programador | O produto e a pessoa ou empresa responsável. Ambos aparecem no consentimento. |
| URL do site | http://localhost:3100 |
| URL da política de privacidade | http://localhost:3100/privacy no exemplo local; publique a sua própria política para clientes. |
| URL do logótipo (opcional) | Imagem acessível publicamente. O FIZ guarda o URL, não o ficheiro. Use HTTPS em produção. |
| URL de instalação | http://localhost:3100/resume — inicia um novo pedido OAuth após o registo. |
| URL de redirecionamento / callback | http://localhost:3100/callback — recebe o resultado OAuth. A correspondência é exata, incluindo porta, caminho e barra final. |
| Permissões autorizadas | company.read, invoicing.read, invoicing.write |
| Testadores | Até 20 emails. Pode adicionar um email antes de existir uma conta FIZ. O testador verifica-o através do código normal de registo/entrada; não há confirmação adicional. |
Copie o ID da aplicação, o client ID (fiz_app_…) e o client secret. O ID da aplicação identifica as ligações de registo; o client ID identifica os pedidos OAuth. O segredo só é mostrado uma vez. Guarde-o no servidor, nunca em JavaScript do navegador, aplicações móveis ou controlo de versões. O FIZ guarda apenas o hash. Se o perder, terá de o rodar explicitamente.
Development e Production são tipos de aplicação
As aplicações Development funcionam no FIZ de produção, apenas para o criador e os testadores indicados. Cada pessoa tem de ser proprietária da empresa que liga. O acesso OAuth de desenvolvimento não exige um plano pago com API. Os dados são reais: não é um ambiente fiscal fictício e qualquer ação fiscal autorizada continua a ser real.
As aplicações Production podem ligar outros clientes após revisão do FIZ. Todos os URLs devem ser HTTPS públicos; localhost não é permitido. Crie uma aplicação Production separada quando estiver pronto: terá outro client ID, segredo e autorizações. O ambiente de uma aplicação não pode ser alterado.
Pode manter até 10 aplicações não arquivadas. Arquivar liberta uma vaga; pausar não. Registe entre 1 e 10 callbacks. A criação e o envio para revisão têm, cada um, um limite partilhado de 10 tentativas por conta e por hora civil.
3. Ligue uma empresa por OAuth
Use Authorization Code + PKCE (S256) com autenticação do cliente no servidor. Uma chave API pertence a uma empresa; uma aplicação obtém consentimento OAuth explícito para cada ligação. Não existe um fluxo client-credentials sem utilizador.
- O servidor gera state + PKCE
- O cliente escolhe empresa e permissões no FIZ
- O FIZ devolve um código ao callback
- O servidor troca-o por tokens
| Issuer / recurso REST | https://api.fiz.co |
|---|---|
| Descoberta | /.well-known/oauth-authorization-server |
| Autorização | GET https://api.fiz.co/oauth/authorize |
| Token | POST https://api.fiz.co/oauth/token |
Inicie a autorização
import { createHash, randomBytes } from 'node:crypto';
const state = randomBytes(32).toString('base64url');
const verifier = randomBytes(32).toString('base64url');
// Store state + verifier in the customer's server-side session with a short TTL.
const url = new URL('https://api.fiz.co/oauth/authorize');
url.search = new URLSearchParams({
response_type: 'code',
client_id: process.env.FIZ_CLIENT_ID,
redirect_uri: 'http://localhost:3100/callback',
state,
code_challenge: createHash('sha256').update(verifier).digest('base64url'),
code_challenge_method: 'S256',
resource: 'https://api.fiz.co',
scope: 'company.read invoicing.read invoicing.write',
}).toString();
// Redirect the customer's browser to url.href.Guarde o verifier e o state na sessão do navegador, no servidor. Devem ser imprevisíveis, novos em cada tentativa e nunca partilhados entre utilizadores. As permissões pedidas devem estar autorizadas nas definições da aplicação.
Valide o callback antes de trocar o código
Exija a sessão original, correspondência exata de state, iss=https://api.fiz.co e exatamente um code ou error. Rejeite parâmetros duplicados e callbacks que misturem sucesso e erro. Um error=access_denied validado significa que o cliente cancelou; permita tentar novamente. Nunca troque um código de um callback não validado.
curl --request POST https://api.fiz.co/oauth/token \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode "client_id=$FIZ_CLIENT_ID" \
--data-urlencode "client_secret=$FIZ_CLIENT_SECRET" \
--data-urlencode "code=$CODE" \
--data-urlencode "code_verifier=$VERIFIER" \
--data-urlencode 'redirect_uri=http://localhost:3100/callback' \
--data-urlencode 'resource=https://api.fiz.co'Envie parâmetros de formulário com client_secret_post, não JSON. Use o verifier original e o mesmo redirect URI e recurso. O pedido de autorização expira em 10 minutos; o código emitido expira em 60 segundos e só pode ser usado uma vez.
A resposta contém access_token, refresh_token, expires_in, token_type e o scope concedido. Guarde os tokens no servidor. Confirme as permissões concedidas em vez de assumir que todas foram aceites.
Cada autorização liga um utilizador, uma empresa e uma aplicação. Consulte GET /company e associe esse ID ao seu cliente antes de escrever. Outra empresa exige outro consentimento; nenhum cabeçalho de tenant pode mudar a empresa do token.
4. Traga um novo cliente para o FIZ
Use o ID de registo da aplicação para iniciar o registo através do parceiro:
const signup = new URL('https://app.fiz.co/auth/signup');
signup.searchParams.set('path', '/auth/app-return?' +
new URLSearchParams({ app: process.env.FIZ_APP_ID }));
// Link to signup.href. Use the application ID, not the fiz_app_ client ID.O cliente verifica o email, cria uma empresa e chega ao passo de ligação à AT. Pode ligar a AT ou escolher Mais tarde. Este percurso salta as perguntas genéricas sobre produtos de interesse e como conheceu o FIZ.
O FIZ regressa depois ao URL de instalação registado. Não acrescenta tokens, ID de empresa, email ou um URL de retorno arbitrário. Esse endpoint inicia uma nova autorização OAuth com state e PKCE novos. No exemplo é /resume; /callback é outro endpoint.
As credenciais AT permanecem no FIZ. A aplicação consulta GET /company para verificar a preparação. Escolher Mais tarde permite ligar para criar rascunhos, mas não dispensa os requisitos de emissão.
5. Faça os primeiros pedidos à API
Confirme a empresa ligada
curl https://api.fiz.co/company \
--header "Authorization: Bearer $ACCESS_TOKEN"A resposta inclui id, name, taxpayerNumber, cae e readiness. Não expõe credenciais AT, dados bancários ou dados pessoais do proprietário.
Se readiness.ready for false, consulte reasons[].code e apresente o actionUrl devolvido como ligação de configuração: AT_CREDENTIALS_REQUIRED, AT_SYNC_REQUIRED ou SERIES_REQUIRED. Atualize a verificação após configurar. O endpoint de escrita faz sempre a verificação final.
Crie o cliente e o artigo desta aplicação
Envie estes JSON para POST /customers e POST /items, com o cabeçalho bearer, Content-Type: application/json e uma Idempotency-Key estável e diferente para cada operação.
{
"name": "Example customer",
"country": "PT"
}{
"name": "Example service",
"type": "SERVICE",
"unitPrice": 10,
"vatRate": "NORMAL"
}Guarde os dois id devolvidos. Escolha a categoria de IVA e o motivo de isenção aplicáveis à empresa; a categoria do exemplo não determina o enquadramento fiscal.
Crie um rascunho
Guarde este JSON como draft.json. Substitua os IDs pelos valores devolvidos e cae por um valor da resposta da empresa. A referência ao artigo é items[].id, não itemId.
{
"type": "INVOICE",
"cae": "62010",
"customerId": "aaaaaaaaaaaaaaaaaaaaaaaa",
"items": [
{
"id": "bbbbbbbbbbbbbbbbbbbbbbbb",
"quantity": 1
}
]
}curl --request POST https://api.fiz.co/invoices \
--header "Authorization: Bearer $ACCESS_TOKEN" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: order-1042-draft' \
--data @draft.jsonConsulte-o com GET /invoices/{id}. Um INVOICE criado neste endpoint é um rascunho. A emissão é uma ação separada, POST /invoices/{id}/issue, com invoicing.issue; envie o expectedUpdatedAt mais recente para evitar emitir uma versão desatualizada. Após emitir, GET /invoices/{id}/pdf obtém o PDF.
6. Permissões e isolamento
| Permissão | Capacidade REST |
|---|---|
company.read | Identidade da empresa, preparação para emissão e lista de séries. |
invoicing.read | Ler faturas, clientes e artigos desta aplicação; PDF de faturas. |
invoicing.write | Criar/alterar/remover rascunhos, clientes e artigos desta aplicação. |
invoicing.issue | Emitir, pagar e cancelar documentos; criar notas de crédito nos registos permitidos desta aplicação. |
invoicing.read_all | Ler faturas, clientes e artigos de toda a empresa. Não permite alterar registos manuais ou de outra aplicação. |
Escolha apenas as permissões necessárias. Por compatibilidade, os metadados da empresa também aceitam a permissão existente de leitura de faturação; nas novas integrações, peça company.read explicitamente. Uma permissão de escrita não concede leitura automaticamente.
Por defeito, a aplicação A não pode ler ou alterar registos da aplicação B ou criados manualmente. Crie um registo de cliente e artigo próprio para a sua aplicação, mesmo que esse comprador já exista no FIZ. O proprietário continua a ver os registos no FIZ.
A referência inclui também endpoints para chaves API. OAuth para aplicações registadas suporta atualmente empresa, séries, faturas, clientes e artigos; documentos de transporte, faturas agendadas, modelos, rotas bancárias e pro formas não são disponibilizados por estas permissões REST. Uma rota sem permissão OAuth explícita é recusada.
O conector MCP usa outro recurso, https://api.fiz.co/mcp. Tokens REST não servem para MCP, nem o inverso. Clientes CIMD pessoais não podem obter acesso REST. Aplicações registadas não podem usar as ferramentas MCP de pro formas.
7. Mantenha ligações fiáveis
Renove os tokens
Os access tokens duram atualmente uma hora; use o expires_in da resposta. Os refresh tokens duram até 90 dias e são rodados a cada utilização. Serialize a renovação por ligação, incluindo entre réplicas do seu servidor, e guarde o novo par de tokens atomicamente.
curl --request POST https://api.fiz.co/oauth/token \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode "client_id=$FIZ_CLIENT_ID" \
--data-urlencode "client_secret=$FIZ_CLIENT_SECRET" \
--data-urlencode "refresh_token=$REFRESH_TOKEN" \
--data-urlencode 'resource=https://api.fiz.co'Se perder a resposta, não reutilize o refresh token às cegas: pode já ter sido rodado, e a reutilização pode revogar a ligação. Trate o resultado como incerto e ofereça nova ligação explícita. Um bloqueio temporário confirmado conserva as credenciais para tentar mais tarde.
Repita escritas conforme o resultado registado
Use uma Idempotency-Key estável por operação, por exemplo order-1042-draft. Use chaves distintas para criar cliente, artigo e emitir. Após timeout, repita a mesma operação com a mesma chave e corpo, parâmetros de caminho e query idênticos para consultar o resultado registado. Nem todos os erros 409 permitem repetição.
As chaves têm 1–128 caracteres ASCII imprimíveis sem espaços. Os resultados são guardados 30 dias e separados por aplicação + utilizador que autorizou + empresa + operação. Novo consentimento do mesmo utilizador mantém esse espaço; outro utilizador tem um diferente. Mantenha a sua própria associação durável entre encomenda e documento. A repetição inclui Idempotent-Replayed.
IN_PROGRESS: enquanto a execução tem um prazo ativo (atualmente 90 segundos), o REST responde 409 com Retry-After. Aguarde e repita com a mesma chave. Uma operação concluída pode devolver o resultado guardado durante os 30 dias de retenção, não apenas dentro desse prazo.
ABANDONED / resultado desconhecido: um prazo expirado sem resultado comunicado, ou uma falha depois de a execução poder ter começado, produz outro 409. Pare as repetições automáticas. Essa chave não pode iniciar outra execução; um registo explicitamente abandonado também não pode devolver um resultado guardado. Esperar não torna a chave reutilizável. Verifique se a operação original teve efeito antes de considerar uma chave nova.
Por exemplo, após POST /invoices/{id}/issue, consulte essa mesma fatura e confirme o estado e número. Se foi emitida, guarde o resultado localmente e não emita novamente. Use uma chave nova apenas depois de confirmar que não houve efeitos e que a operação original já não está em execução. Se não conseguir confirmar, contacte o suporte para evitar duplicados. Uma rejeição de validação antes da execução permite repetir o pedido original inalterado; um payload corrigido é um pedido novo e exige outra chave.
Pausa, revogação e rotação
Pausar, suspender pelo FIZ ou devolver uma aplicação Production para revisão bloqueia temporariamente o uso, conservando as credenciais. Arquivar, desligar ou remover um testador pode revogar acesso. Reduzir permissões invalida autorizações com permissões antigas; volte a ligar com as novas. Rodar o segredo substitui imediatamente o anterior: atualize a configuração do servidor. Não substitui a revogação de tokens já emitidos.
Os clientes podem desligar em Definições → Integrações. Pare tarefas de ligações revogadas e ofereça uma ação explícita para voltar a ligar.
8. Resolva erros frequentes
| Resultado | O que fazer |
|---|---|
| Aplicação indisponível no consentimento | Verifique pausa/arquivo/suspensão, aprovação Production, identidade do criador/testador Development e permissões pedidas. Um novo testador pode registar-se com o email indicado. |
| Plano com API necessário | Uma ligação Production exige um plano da empresa com API. O teste Development está isento; não altera a subscrição da empresa. |
invalid_client | Verifique client ID, segredo atual e codificação do formulário. Não altere nem remova espaços de um segredo silenciosamente. |
invalid_grant | Código/token expirado, usado, revogado ou já não permitido. Volte a ligar explicitamente; não repita refresh em ciclo. |
temporarily_unavailable | Conserve as credenciais, pause a tarefa e tente mais tarde com espera progressiva. Não force todos os clientes a voltar a ligar. |
| REST 401 | Verifique validade, revogação e audience exata. Uma aplicação suspensa também falha introspeção. Distinga bloqueio temporário de autorização revogada. |
| REST 403 | Verifique permissões concedidas, acesso/propriedade da empresa, plano Production e suporte OAuth da rota. |
| REST 400 | Consulte a validação e a preparação da empresa. Verifique maiúsculas dos enums, CAE, IDs e campos obrigatórios na referência. |
| REST 409 — IN_PROGRESS | A resposta indica que o pedido continua em processamento e inclui Retry-After. Aguarde e repita com a mesma chave e pedido idêntico. |
| REST 409 — ABANDONED / resultado desconhecido | A resposta indica que o pedido anterior pode ter tido efeito; não inclui prazo para repetição. Pare as repetições automáticas: a chave está consumida para execução. Consulte os documentos/registos existentes. Só use uma chave nova após confirmar que a primeira tentativa não teve efeito e já não está em execução; caso contrário, reconcilie ou contacte o suporte. Estes nomes descrevem resultados internos: consulte a mensagem HTTP e Retry-After, não um campo outcome inexistente. |
| REST 422 | A mesma chave foi usada com outro payload. Recupere a operação original; não mude continuamente a chave para contornar o conflito. |
| 429 | Respeite Retry-After, use espera progressiva com jitter e distribua tarefas no tempo. REST permite atualmente 300 pedidos/minuto por autorização/empresa; tokens têm limites separados por aplicação/IP. |
Ao contactar suporte, indique ID da aplicação, ambiente, endpoint, hora UTC, estado HTTP e ID do pedido/idempotência. Não envie segredos, tokens ou credenciais AT.
9. Prepare a abertura a clientes
- Teste uma ligação Development como criador e como testador, incluindo registo de conta nova. Verifique cancelamento, remoção de testadores, escolha da empresa e repetições.
- Crie uma aplicação Production separada com nome real, URLs HTTPS públicos, política de privacidade e apenas as permissões necessárias.
- Envie-a para revisão em Aplicações de programador. Trate dúvidas através do suporte FIZ. A aprovação é necessária antes de ligar clientes.
- Guarde segredos e tokens em armazenamento seguro/cifrado no servidor. Substitua a memória do exemplo por ligações duráveis por cliente e um bloqueio de refresh partilhado.
- Verifique associação da empresa, idempotência, revogação e preparação para emissão. Use a sua interface para ações fiscais deliberadas.
- Configure as credenciais da aplicação Production e obtenha novo consentimento. As autorizações Development não são migradas.
Editar definições aprovadas devolve a aplicação a Draft e exige nova revisão; pausa/retoma e rotação do segredo mantêm o estado da revisão. Planeie as alterações antes de convidar clientes.
O exemplo é um servidor local de aprendizagem, não um serviço para vários clientes pronto a publicar. Tokens e chaves de pedido desaparecem ao reiniciar; isso não revoga autorizações FIZ. Não dependa dessa memória para deduplicação ou recuperação em produção.