Pular para o conteúdo
NFSeIA
Páginas da documentação

Prévia: a API abre junto com o painel.

Gatilhos de pagamento

Recebeu, emitiu. Um gatilho é um endereço de entrada só seu: o seu sistema avisa que um pagamento foi confirmado e o NFSeIA emite a nota fiscal de serviço a partir de um modelo, sem ninguém clicar. O mesmo pagamento nunca gera duas notas.

Serve para qualquer meio de pagamento: no ponto do seu sistema em que o pagamento é confirmado (o aviso do seu banco ou da sua plataforma de cobrança), mande o aviso para o gatilho. Conectores prontos para os meios de pagamento mais usados chegam depois do lançamento.

1. Crie o gatilho com o modelo da nota

O modelo diz como a nota sai. Tomador e valor podem ser fixos ou vir em cada aviso; o resto de serviço e impostos, se você não informar, vem dos padrões da empresa. A origem diz de onde vêm os pagamentos: um nome curto para o seu sistema de cobrança e a conta nele. Ela entra na identidade de cada nota e não muda depois da criação.

Terminal
curl -X POST https://api.nfseia.com.br/v1/gatilhos \
  -H "Authorization: Bearer $NFSEIA_CHAVE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "nome": "Assinaturas do sistema",
    "origem": { "provedor": "meu-sistema", "conta": "principal" },
    "modelo": {
      "usar_valor_do_aviso": true,
      "tomador": null,
      "servico": { "descricao": "Assinatura mensal do sistema de gestão" },
      "valores": {}
    }
  }'

A resposta traz o url do gatilho e o segredo (gsec_...), este uma única vez:

JSON
{
  "id": "gat_01JC91D3F6H9K2M5P8R1T4W7Y0",
  "origem": { "provedor": "meu-sistema", "conta": "principal" },
  "url": "https://api.nfseia.com.br/v1/gatilhos/gat_01JC91D3F6H9K2M5P8R1T4W7Y0/eventos",
  "segredo": "gsec_6fQ2xN8vR1kT4mW7zB0cE3hJ5",
  "status": "ativo"
}
  • usar_valor_do_aviso: true: o valor de cada nota vem do aviso. Com false, vale modelo.valores.valor_servico, o mesmo para todo pagamento.
  • tomador: null: o tomador vem em cada aviso. Para um cliente só, fixe o tomador no modelo.
  • No MVP, gatilho não aceita intermediário nem retido_pelo_intermediario.

2. Mande o aviso quando o pagamento for confirmado

O endereço do gatilho é público e não usa chave de API: o aviso vale só com a assinatura NFSeIA-Assinatura, o HMAC-SHA256 de {t}.{corpo} com o segredo do gatilho, igual à dos webhooks, no sentido contrário.

Em Node:

Node
import { createHmac } from 'node:crypto';

export async function avisarPagamento(pagamento) {
  const corpo = JSON.stringify({
    pagamento_id: pagamento.id,
    valor: pagamento.valor, // "89.90"
    pago_em: pagamento.pagoEm, // "2026-11-05T16:42:07-03:00"
    tomador: { documento: pagamento.cliente.documento, nome: pagamento.cliente.nome, email: pagamento.cliente.email },
  });
  const t = Math.floor(Date.now() / 1000);
  const v1 = createHmac('sha256', process.env.NFSEIA_SEGREDO_GATILHO).update(`${t}.${corpo}`).digest('hex');
  const resposta = await fetch(process.env.NFSEIA_URL_GATILHO, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'NFSeIA-Assinatura': `t=${t},v1=${v1}` },
    body: corpo,
    signal: AbortSignal.timeout(35_000),
  });
  return { status: resposta.status, nota: await resposta.json() };
}

Em Python:

Python
import hashlib
import hmac
import json
import os
import time

import requests


def avisar_pagamento(pagamento: dict) -> requests.Response:
    corpo = json.dumps({
        "pagamento_id": pagamento["id"],
        "valor": pagamento["valor"],  # "89.90"
        "pago_em": pagamento["pago_em"],
        "tomador": pagamento["tomador"],
    })
    t = str(int(time.time()))
    v1 = hmac.new(os.environ["NFSEIA_SEGREDO_GATILHO"].encode(), f"{t}.{corpo}".encode(), hashlib.sha256).hexdigest()
    return requests.post(
        os.environ["NFSEIA_URL_GATILHO"],
        data=corpo.encode(),
        headers={"Content-Type": "application/json", "NFSeIA-Assinatura": f"t={t},v1={v1}"},
        timeout=35,
    )

Assine o corpo exatamente como ele vai ser enviado: qualquer espaço a mais muda a assinatura. Gere t na hora de cada envio, inclusive nas novas tentativas: o NFSeIA recusa t a mais de 5 minutos do horário atual, no passado ou no futuro.

3. O que volta

A resposta é a mesma da emissão pela API:

  • 201: nota autorizada.
  • 200: este pagamento já tinha nota; volta a mesma, nada é emitido.
  • 202: a SEFIN demorou; a nota fica pendente e o webhook avisa quando sair.
  • 400 dados_invalidos ou 422 nota_rejeitada: corrija e mande o aviso de novo.
  • 401 assinatura_invalida: assinatura errada ou com t a mais de 5 minutos do horário atual.
  • 429: limite de avisos. O limite por IP vale antes de conferir a assinatura (inclusive para assinatura inválida); depois dela, vale o limite por gatilho e o de emissões da empresa.
  • 409 estado_invalido: o gatilho está pausado. Mande de novo depois de reativar.

Uma nota por pagamento

A identidade da nota é pagamento:{provedor}:{conta}:{pagamento_id}, com provedor e conta da origem do gatilho, e é reservada antes de qualquer envio à SEFIN. Gatilhos com a mesma origem compartilham a identidade. Pode mandar o mesmo aviso quantas vezes quiser, por um ou por outro gatilho (o seu sistema tentou de novo, o aviso chegou duas vezes do seu banco): a nota é uma só. Por isso o pagamento_id precisa ser o id do pagamento, não do cliente nem do pedido, se um pedido tiver mais de um pagamento.

O prefixo pagamento: é reservado: a emissão manual pela API recusa referência que comece com ele (400 referencia_reservada).

Cuidar do gatilho

  • PATCH /gatilhos/{id} com "status": "pausado" para de emitir na hora; "ativo" volta.
  • POST /gatilhos/{id}/rotacionar-segredo troca o segredo. Com {"modo": "normal"}, o anterior vale por mais 24 horas (no máximo um anterior por vez); com {"modo": "emergencia"}, é revogado na hora.
  • DELETE /gatilhos/{id} apaga o endereço. Notas já emitidas não mudam.

Gatilho criado com chave de teste emite no ambiente de teste. Comece por ele.