API e Integrações

Conecte seu ERP, e-commerce ou sistema legado à plataforma FinzioFiscal via API REST de alta performance.

Portal do Desenvolvedor

Acesse o menu Desenvolvedor no topo ou lateral da plataforma para gerenciar suas credenciais de integração, consultar logs de chamadas e visualizar a especificação interativa Swagger/OpenAPI.

Criando Credenciais de Integração

Para que um sistema externo envie ou consulte notas fiscais, você deve criar um par de chaves de API:

  1. 1Na aba Credenciais de API, clique no botão Criar Credencial.
  2. 2Defina um nome de identificação (ex: “ERP Protheus Produção” ou “Loja Virtual Shopify”) e escolha o ambiente (Produção ou Homologação).
  3. 3Copie o Client ID e o Client Secret gerados.

O Client Secret é exibido apenas uma vez no momento da criação. Guarde-o em local seguro (como variáveis de ambiente do seu backend). Caso perca o segredo, será necessário gerar uma nova credencial.

Autenticação nas requisições

A API tem duas formas de autenticar, para dois usos diferentes. Não as confunda:

1. Credencial de integração (Client ID e Client Secret), para sistemas externos (ERP, e-commerce). Vale nas rotas /integration/* e usa HTTP Basic: o Client ID é o usuário e o Client Secret é a senha.

Authorization: Basic base64(clientId:clientSecret)

2. Login de usuário (token JWT), para o que a tela também faz: listar e baixar documentos, relatórios e cadastros, com as permissões do usuário. Chame POST /auth/login com e-mail e senha e envie o token recebido:

Authorization: Bearer <accessToken>

Sessão de API: sem renovação automática

O login feito diretamente pela API cria uma sessão de API. Ela é diferente da sessão da tela: não recebe refreshToken, vale até o token expirar e é encerrada sozinha se ficar um período sem requisições (30 minutos por padrão). Quando isso acontecer, a API responde 401 e basta fazer login de novo.

Para encerrar a sessão antes, chame POST /auth/logout. A sessão de API não derruba a sessão da tela do mesmo usuário, e o contrário também vale. Em Sessões & Histórico de Login ela aparece com o canal “API”.

A sessão da tela (que usa o cabeçalho X-Client-Channel: web) é única por usuário: entrar em outro dispositivo encerra a anterior. Integrações não precisam enviar esse cabeçalho.

Referência interativa e coleção Postman

A referência completa da API (Swagger/OpenAPI) fica em /docs, e o mesmo documento em JSON em /docs/json. A coleção Postman, gerada desse mesmo documento, pode ser baixada em /docs/postman ou na área de chaves de API. Importe a coleção e preencha as variáveis: baseUrl; clientId e clientSecret para as rotas de integração. Para as demais, execute a requisição de login da coleção, que guarda o token na variável tokenSessao automaticamente.

Em produção, a referência pode exigir que você esteja autenticado, conforme a configuração do ambiente. Se o endereço pedir login, use a conta de um usuário da organização.

Principais Endpoints REST

POST/integration/nfe-emissions

Emissão de NF-e ou NFC-e pela integração. Recebe o JSON com destinatário, itens e tributação, assina, transmite à SEFAZ e devolve a chave de acesso e o protocolo. Credencial de integração.

POST/integration/nfe-emissions/batch

Emissão em lote: envia um arquivo ZIP com vários documentos, cada um validado como na emissão unitária. Credencial de integração.

POST/integration/emission-commands

Emissão assíncrona com o mesmo JSON da rota síncrona. Responde 202 na hora com o commandId, e a transmissão segue em fila, na ordem de chegada por CNPJ emitente, com nova tentativa automática e consulta à SEFAZ antes de reenviar. Repetir a mesma idempotencyKey com o mesmo corpo devolve o comando com 200; com outro corpo, 409. O andamento sai em GET /integration/emission-commands/:id ou /by-idempotency-key/:key. Credencial de integração.

GET/integration/nfe-emissions/by-key/:accessKey

Consulta uma emissão pela chave de acesso. O XML e o DANFE saem em /integration/nfe-emissions/:id/xml e /:id/danfe. Credencial de integração.

GET/nfes

Lista as NF-e recebidas, com filtros por período de emissão, CNPJ, status, número e chave de acesso, e paginação. Existem também /ctes e /nfse. Login de usuário.

GET/fiscal-documents/:kind/:accessKey/xml

Download do XML original de um documento recebido (kind é nfe, cte ou nfse). Login de usuário.

POST/nfe-emissions/:id/epec

Registra e transmite o evento prévio de EPEC (Emissão em Contingência) à SEFAZ Virtual RS quando o autorizador normal está indisponível, liberando a operação comercial da empresa. A nota definitiva sai assim que a SEFAZ normal volta, com a mesma chave de acesso do evento prévio. Login de usuário.

GET/fiscal-documents/xml-batch-download

Baixa XMLs em lote de um tipo por chamada (tipo), filtrados por chave, número, CNPJ ou período, com o XML em base64 na resposta paginada. As datas aceitam AAAA-MM-DD, DD.MM.AAAA e DD/MM/AAAA; data inválida responde 400. Na API, os filtros informados se combinam (chave e período, por exemplo, valem juntos). Login de usuário.

Consulte o Swagger Interativo em /docs para testar as chamadas e ver o esquema completo de cada campo.

Webhooks: o Finzio avisa o seu sistema

Em vez de consultar a API de tempos em tempos, cadastre em Administração, Webhooks o endereço do seu sistema e escolha os eventos. O Finzio faz um POST com JSON a cada evento. O endereço precisa ser público e, em produção, usar HTTPS. Redes internas e redirecionamentos são recusados.

Eventos

  • document.received: Um documento novo (NF-e, CT-e ou NFS-e) entrou no acervo da empresa.
  • manifestation.registered: A SEFAZ registrou uma manifestação do destinatário ou um desacordo de CT-e.
  • emission.authorized: Uma NF-e, NFC-e, CT-e ou MDF-e emitida foi autorizada pela SEFAZ.
  • emission.canceled: Uma NF-e ou NFC-e emitida foi cancelada.
  • emission.corrected: Uma carta de correção foi registrada.
  • emission.command.succeeded: Um comando de emissão assíncrona chegou ao resultado fiscal.
  • emission.command.failed: Um comando esgotou as tentativas sem resposta da SEFAZ.

Corpo

O corpo traz só ids, chave de acesso, códigos e datas. XML e DANFE saem pela API autenticada, pelo link em data.links. Campo novo pode aparecer a qualquer momento: ignore o que não conhecer. Mudança de significado sai numa versão nova do evento (eventVersion).

{
  "id": "5f0c6c1e-8a4e-4c4b-9a53-1f1f3a0d2b77",
  "eventType": "document.received",
  "eventVersion": 1,
  "occurredAt": "2026-09-28T12:00:00.000Z",
  "tenantId": "…",
  "companyId": "…",
  "companyCnpj": "11222333000181",
  "aggregate": { "type": "received-document", "id": "3526…6785" },
  "data": {
    "documentId": "…",
    "documentKind": "NFE",
    "accessKey": "3526…6785",
    "issuedAt": "2026-09-27T18:20:00.000Z",
    "links": { "self": "/fiscal-documents/nfe/…" }
  }
}

Cabeçalhos e verificação

  • X-Finzio-Event-Id: id do evento, igual ao id do corpo e o mesmo em toda reentrega. Guarde e descarte o que já processou.
  • X-Finzio-Event-Type: o tipo do evento.
  • X-Finzio-Timestamp: segundos Unix do envio. Recuse o que estiver a mais de 5 minutos do seu relógio: é o que impede alguém de reenviar uma requisição capturada.
  • X-Finzio-Signature: v1= seguido do HMAC-SHA256, em hexadecimal, de timestamp.corpo com o segredo da assinatura.
import { createHmac, timingSafeEqual } from 'node:crypto';

// body: o corpo CRU da requisição, antes de qualquer JSON.parse.
export function webhookValido(headers, body, segredo) {
  const ts = Number(headers['x-finzio-timestamp']);
  if (!Number.isInteger(ts) || Math.abs(Date.now() / 1000 - ts) > 300) return false;
  const esperado = Buffer.from(
    'v1=' + createHmac('sha256', segredo).update(ts + '.' + body).digest('hex'),
  );
  // Na rotação de segredo chegam duas assinaturas separadas por vírgula.
  return String(headers['x-finzio-signature'])
    .split(',')
    .some((s) => {
      const recebido = Buffer.from(s.trim());
      return recebido.length === esperado.length && timingSafeEqual(recebido, esperado);
    });
}

Entrega, repetição e ordem

Responda 2xx em até 10 segundos e processe depois, em fila. Qualquer outro retorno, ou a falta de resposta, gera nova tentativa: 30 segundos, dobrando até 6 horas, com uma variação aleatória, até 8 tentativas. Depois disso a entrega fica como falha na tela, de onde pode ser reenviada com o mesmo event id. A entrega é ao menos uma vez: o mesmo evento pode chegar duas vezes, e eventos de documentos diferentes podem chegar fora de ordem. Para o mesmo documento, use occurredAt.

O segredo aparece uma única vez, ao criar a assinatura ou ao rotacionar. Na rotação, o segredo anterior continua assinando por 24 horas e as duas assinaturas chegam no mesmo cabeçalho, separadas por vírgula.
Desenvolvido porGSATI Tecnologia da Informação