NF-e e Split Payment: preparando um e-commerce para o novo cenário fiscal
Como planejar a emissão de Nota Fiscal Eletrônica em um e-commerce Astro + Cloudflare e preparar a arquitetura de pagamentos para o split payment da reforma tributária.
O problema em duas frentes
Um e-commerce brasileiro que vende produto físico precisa resolver duas questões fiscais que costumam ser tratadas tarde demais no ciclo de desenvolvimento:
- Hoje: emitir Nota Fiscal Eletrônica (NF-e) a cada venda, de forma automatizada e auditável.
- A partir de 2027: conviver com o split payment da reforma tributária, em que a própria liquidação financeira segrega CBS e IBS antes de o valor líquido chegar ao lojista.
Este artigo documenta o planejamento das duas frentes para uma stack Astro + Cloudflare + Supabase, com foco em decisões de arquitetura que não precisem ser refeitas quando as regras mudarem.
Parte 1 — Nota Fiscal Eletrônica
Qual documento emitir
A primeira decisão não é técnica, é fiscal. Para venda de produto físico pela internet, o documento é a NF-e modelo 55. O resumo:
| Operação | Documento |
|---|---|
| Venda de produto físico pelo site | NF-e modelo 55 |
| Venda presencial ao consumidor em loja | NFC-e modelo 65 |
| Prestação de serviço (desenvolvimento, consultoria) | NFS-e |
| Venda com produto e serviço separáveis | Avaliação caso a caso |
Um detalhe que gera confusão: dados bancários não participam da emissão fiscal. A conta que recebe o Pix serve para conciliação do pagamento; a nota é emitida com os dados cadastrais e tributários da empresa.
Por que não integrar direto com a SEFAZ
A NF-e envolve assinatura digital de XML, validação contra schemas XSD, webservices fiscais, tratamento de rejeições, contingências e controle rigoroso de numeração. Implementar isso do zero em um Worker é reinventar uma roda cheia de arestas regulatórias.
A solução prática é uma API fiscal intermediária: o backend envia JSON, o provedor assina, transmite à SEFAZ e devolve o resultado por webhook.
Cliente
│
▼
Loja (Astro)
│
▼
Worker / API server-side
├── Banco de pedidos
├── Integração de pagamento
└── API fiscal ──► SEFAZ
Escolhendo o provedor (sem casar com ele)
A avaliação de julho de 2026 mapeou quatro caminhos com perfis bem diferentes:
| Cenário | Opção | Custo |
|---|---|---|
| Validação, pouca venda | Emissor gratuito do Sebrae (manual) | R$ 0 |
| Automação + ERP | Bling Cobalto (NF-e ilimitadas, API OAuth 2.0, estoque/pedidos) | R$ 60/mês |
| API fiscal pura | Focus NFe (Solo ~100 docs; Retail exige confirmar endpoints de NF-e) | R$ 59,90–89,90/mês |
| Volume alto, controle total | NFePHP/SPED-NFe em servidor próprio | R$ 0 + infra e manutenção |
A Nuvem Fiscal foi descartada: anunciou desativação do serviço para 31 de julho de 2026 — um lembrete de que provedor fiscal também morre.
Exatamente por isso a integração precisa ser agnóstica ao provedor — o mesmo padrão de ports & adapters que se usa para PSPs de pagamento vale para o fiscal. Com uma porta única (FiscalProviderPort), a fase de validação roda com um adapter manual: o pagamento confirmado enfileira o pedido, o operador emite a nota no emissor gratuito do Sebrae e registra chave de acesso, número e XML no admin. Quando o volume justificar a mensalidade, entra um adapter automatizado (Bling ou Focus) — mesma tabela, mesmos estados, zero mudança no domínio. O caminho self-hosted (NFePHP exige PHP, criptografia e SOAP fora do alcance de um Worker) fica registrado como opção futura, não como ponto de partida: o custo nominal zero cobra caro em manutenção de schemas, contingência e responsabilidade fiscal.
Certificado digital
Emissão em nuvem exige certificado e-CNPJ A1 (arquivo). O A3 depende de token ou cartão físico e não serve para servidores. O certificado não vai para o repositório nem para o Worker: é cadastrado no cofre do próprio provedor fiscal.
O que o contador define antes de qualquer código
O maior risco do projeto não é a chamada HTTP — é o cadastro tributário. Cada produto precisa de:
| Campo | Quem define |
|---|---|
| NCM | Contador |
| CFOP (interno/interestadual) | Contador |
| CST ou CSOSN | Contador (regime) |
| CEST (quando houver) | Contador |
| Origem da mercadoria | Contador |
| Alíquotas | Contador |
Esses parâmetros afetam o cálculo do imposto e a autorização da nota. Não devem ser escolhidos pelo desenvolvedor por aproximação. O projeto só sai da fase de planejamento quando existir uma ficha tributária validada: razão social, IE habilitada, regime, CRT, série e numeração da NF-e, natureza da operação e o perfil de cada produto.
Fluxo de emissão
A nota não é emitida porque alguém abriu o checkout. O gatilho é a confirmação do pagamento (ou o momento fiscal definido pelo contador):
pedido_criado → aguardando_pagamento → pagamento_confirmado
→ emissao_fiscal_pendente → nfe_processando
├──► nfe_autorizada
└──► nfe_rejeitada
A emissão é normalmente assíncrona: o backend envia a solicitação com uma referência única, o provedor processa e um webhook informa autorização ou rejeição. O sistema então armazena chave de acesso, XML e DANFE, envia o DANFE ao cliente e libera o pedido para produção/envio.
Estado fiscal não é um booleano
Um campo invoiceIssued = true não representa a realidade. O modelo precisa distinguir:
| Estado | Significado |
|---|---|
not_requested | Emissão ainda não solicitada |
pending | Aguardando envio |
processing | Em análise (API ou SEFAZ) |
authorized | NF-e autorizada |
rejected | Dados recusados |
cancel_pending | Cancelamento solicitado |
cancelled | NF-e cancelada |
contingency | Emissão em contingência |
manual_review | Precisa de intervenção humana |
E o documento fiscal vive em tabela própria, separada do pedido:
create table fiscal_documents (
id uuid primary key,
order_id uuid not null references orders(id),
provider text not null,
provider_reference text not null unique,
status text not null,
access_key text,
xml_url text,
danfe_url text,
rejection_code text,
rejection_message text,
request_payload jsonb,
response_payload jsonb,
created_at timestamptz not null default now()
);
O provider_reference, derivado do identificador interno do pedido, funciona como chave de idempotência: uma requisição repetida por falha de rede não pode gerar uma segunda nota para o mesmo pedido.
Segurança na borda
Regras não negociáveis para a integração em Cloudflare:
- Token fiscal e segredo de webhook só existem como secrets do Worker — nunca em variável pública, HTML ou repositório.
- O navegador nunca envia preço, NCM ou imposto para o endpoint de emissão. O payload fiscal é montado no servidor, a partir do pedido pago carregado do banco.
- O webhook valida assinatura, identifica a nota pela referência, descarta eventos duplicados e só então atualiza o estado.
- CPF/CNPJ do cliente vai apenas ao backend e não aparece em logs ou mensagens de erro.
Parte 2 — Split payment
O que muda
Hoje, o lojista recebe R$ 100,00 e recolhe os tributos depois. No split payment, a instituição financeira segrega os tributos durante a liquidação: uma parcela vai para a CBS, outra para o IBS, e só o líquido é creditado ao fornecedor. Não é um imposto novo — é um mecanismo de recolhimento automático embutido no pagamento.
Quem fala com a API do governo (spoiler: não é você)
A Plataforma Pública de Split Payment não é uma API para lojas ou SaaS. Ela é um hub entre PSPs e o fisco:
Cliente → Sua aplicação → Banco/PSP → Plataforma de Split Payment
├── Receita Federal (CBS)
└── Comitê Gestor (IBS)
A documentação trata o cliente da API como PSP homologado, com mTLS, rate limiting, long polling e política de erros de infraestrutura financeira. Para o desenvolvedor de aplicação, a conclusão é direta:
Seu sistema não conversa com a API do CGIBS. Ele conversa com um PSP que ofereça Pix dinâmico, webhooks, dados de liquidação e, futuramente, a vinculação com o documento fiscal.
O elo que quase ninguém tem hoje
O split “superinteligente” — que usa a situação tributária real do documento fiscal em vez de um percentual fixo — depende de vincular documento fiscal ↔ transação financeira antes da liquidação. Isso conecta três objetos que a maioria dos sistemas trata separadamente:
pedido ↔ documento fiscal ↔ pagamento
Quem não fizer essa vinculação cai no procedimento alternativo: retenção estimada com devolução posterior do excesso. Ou seja: a Parte 1 deste artigo (NF-e bem modelada, ligada ao pedido e ao pagamento) é literalmente o pré-requisito da Parte 2.
Não há obrigação em 2026 — há dever de casa
A documentação técnica é explícita: a implantação efetiva está prevista a partir de 2027; os campos publicados em 2026 são preparatórios. Não se justifica reconstruir nada agora. O momento é de preparação arquitetural:
- Separar claramente pedido, documento fiscal e pagamento no modelo de dados.
- Usar Pix dinâmico como padrão em cobrança comercial (tem
txIdpróprio e participa de todos os fluxos; o estático serve para pagamento informal). - Guardar
txIdee2eIdde cada liquidação. - Tratar webhooks com idempotência (chave única por evento, payload bruto armazenado, retries com backoff).
- Manter no modelo a distinção
valor bruto ≠ tributos ≠ valor líquidoecobrança criada ≠ paga ≠ liquidada. - Acessar todo PSP por uma porta abstrata com adapters:
export interface PaymentProviderPort {
createPixCharge(input: CreateChargeInput): Promise<PaymentIntent>;
getPaymentStatus(providerPaymentId: string): Promise<PaymentStatus>;
verifyWebhook(headers: Record<string, string>, rawBody: Uint8Array): Promise<VerifiedPaymentEvent>;
refundPayment(input: RefundInput): Promise<RefundResult>;
}
Quando o PSP publicar a implementação compatível com split payment, a mudança se resume a um novo adapter — o domínio, os pedidos e o frontend permanecem intactos.
Conclusão
O plano consolidado para as duas frentes:
Documento fiscal: NF-e modelo 55, atrás de uma porta agnóstica de provedor
Fase 1 (validação): adapter manual — emissor gratuito do Sebrae + registro no banco
Fase 2 (automação): adapter Bling Cobalto (candidato) ou Focus NFe (alternativa)
Certificado: e-CNPJ A1, no cofre do provedor
Gatilho: pagamento confirmado
Retorno: webhook idempotente → XML + DANFE + chave de acesso
Pagamentos: Pix dinâmico, porta agnóstica de PSP, txId/e2eId persistidos
Split payment: nada a implementar em 2026; arquitetura pronta para 2027
A parte difícil não é o código — é a disciplina de tratar NCM, CFOP, CSOSN e alíquotas como dados do contador, e de modelar pagamento e nota fiscal como entidades ligadas desde o primeiro dia.
Referências
- Documentação da API Focus NFe — emissão via
POST /v2/nfe, referência única e webhooks - Planos Focus NFe
- Planos e preços do Bling · NF-e no Bling
- Emissor de NF-e gratuito do Sebrae
- NFePHP/SPED-NFe — biblioteca livre para emissão direta à SEFAZ
- Manual NF-e — SEFAZ-RJ
- Nota Técnica CT-e 2026.001 — vinculação do arranjo de pagamento
- FAQ da Reforma Tributária — SEFAZ-BA