# Gatilhos de pagamento

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

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.

```sh
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](https://nfseia.com.br/docs/webhooks), no sentido contrário.

Em Node:

```js
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:

```py
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.
