Webhooks

A emissão, o cancelamento e a substituição são assíncronos. O webhook avisa o seu sistema quando a Sefin Nacional autoriza, rejeita, cancela ou substitui a nota, e quando o certificado de um contribuinte está para vencer.

Eventos

Tipo Quando
invoice.authorized A Sefin Nacional autorizou a NFS-e.
invoice.rejected A Sefin Nacional rejeitou a nota, ou o Nota4You recusou antes do envio (por exemplo, certificado vencido).
invoice.cancelled A Sefin Nacional registrou o cancelamento da nota.
invoice.substituted A Sefin Nacional autorizou a nota substituta. O corpo traz a nota original, com substitute_invoice_id.
invoice_event.rejected A Sefin Nacional recusou um cancelamento. O corpo traz data.invoice_event com os códigos em rejection_codes.
certificate.expiring O certificado de um contribuinte vence em 30, 15, 7, 1 ou 0 dias. Um evento por certificado e por dia de aviso.
webhook.test Você pediu um envio de teste.

Cadastro

Em Configurações > Webhooks ou pela API (/api/v1/webhook_endpoints, escopo webhooks:manage): endereço https, eventos, descrição e a opção include_personal_data. Até 10 endereços por conta. O segredo (whsec_...) aparece só na criação e na troca. Na tela de cada webhook você vê as entregas, envia um teste e reenvia uma entrega.

O esquema de cada corpo está na seção webhooks do OpenAPI.

Corpo

{
  "id": "0f6b2c1e-8f1d-4f7a-9a51-2a3c9b0e7d11",
  "type": "invoice.authorized",
  "created_at": "2026-10-19T14:32:05-03:00",
  "data": {
    "invoice": {
      "id": "4a77...", "taxpayer_id": "9c1e...", "status": "authorized",
      "access_key": "3550308...", "nfse_number": "42", "rejection_codes": [],
      "customer": { "id": "8bb9..." }
    }
  }
}

Sem a opção include_personal_data, o corpo não traz dados pessoais: o tomador vai só com o id. Para os detalhes, consulte GET /api/v1/invoices/:id.

Dados pessoais

Com include_personal_data: true, o corpo traz customer e, quando a nota tiver, recipient e intermediary, cada um com document_type, document, name, email, phone e address. No certificate.expiring, a opção acrescenta subject_document (o CNPJ ou CPF do contribuinte). Ligue só se o seu sistema precisar desses dados e tiver base legal para recebê-los (LGPD). Veja Privacidade.

Certificado vencendo

{
  "id": "5c1d...",
  "type": "certificate.expiring",
  "created_at": "2026-12-11T06:00:00-03:00",
  "data": {
    "certificate": {
      "id": "7645...", "taxpayer_id": "fc3c...",
      "not_after": "2027-01-10T12:00:00-03:00", "days_left": 30
    }
  }
}

Assinatura

Cada envio traz o cabeçalho X-Nota4you-Signature: t=<segundos>,v1=<hex>, onde v1 é HMAC-SHA256(segredo, "<t>.<corpo bruto>"). Confira antes de confiar no corpo e recuse envios com mais de 5 minutos:

timestamp, signature = header.scan(/t=(\d+),v1=(\h+)/).first
expected = OpenSSL::HMAC.hexdigest("SHA256", secret, "#{timestamp}.#{raw_body}")
valid = ActiveSupport::SecurityUtils.secure_compare(expected, signature) &&
        Time.at(timestamp.to_i) > 5.minutes.ago

Outros cabeçalhos: X-Nota4you-Event-Id, X-Nota4you-Event-Type, X-Nota4you-Delivery-Attempt.

Novas tentativas

Uma resposta 2xx conclui o envio. Redirecionamentos contam como falha. Tempo limite: 5 s para conectar, 10 s para responder. Depois de uma falha, tentamos de novo em 1 min, 5 min, 30 min, 1 h, 2 h, 4 h, 8 h e 8 h. Todos os envios de um evento têm o mesmo id: use-o para ignorar repetições.