Quickstart
Você vai sair daqui com uma NFC-e autorizada de verdade (no sandbox, com mock SEFAZ) em menos de 5min.
Sandbox vs Produção: todas as URLs aqui usam sandbox.zfiscoo.zek.app.br.
Pra produção, troque pra api.zfiscoo.zek.app.br + sua API key real (fk_live_...).
1. Confere se o sandbox tá no ar
curl https://sandbox.zfiscoo.zek.app.br/healthz
# {"status":"ok","ts":"2026-..."}2. Emite a NFC-e
curl -X POST https://sandbox.zfiscoo.zek.app.br/v1/nfce \
-H "Authorization: Bearer fk_sandbox_public" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pedido-001" \
-d '{
"issuer_id": "iss_demo_sp",
"external_ref": "pedido-001",
"items": [
{
"description": "X-Burger Combo",
"quantity": 1,
"unit_price": 32.90,
"ncm": "21069090",
"cfop": "5102",
"unit": "UN",
"cst_icms": "00"
}
],
"payment": {
"method": "dinheiro",
"amount": 32.90
}
}'A linha destacada é o Idempotency-Key — se você reenviar o mesmo curl, recebe a mesma resposta (com header
Idempotency-Replay: true). É o que evita NFC-e duplicada em caso de retry de network.
Resposta:
{
"id": "nfce_01HXYZ...",
"status": "processing",
"external_ref": "pedido-001",
"created_at": "2026-05-11T10:23:45.123Z"
}3. Acompanha o status (3 opções)
Polling
Boa pra scripts simples e batch:
curl https://sandbox.zfiscoo.zek.app.br/v1/nfce/nfce_01HXYZ... \
-H "Authorization: Bearer fk_sandbox_public"
# {
# "id": "nfce_01HXYZ...",
# "status": "authorized",
# "access_key": "35260100000000000000550010000000011000000017",
# "protocolo": "135260000000001",
# "xml_url": "https://...",
# "danfe_url": "https://...",
# "qrcode_url": "https://..."
# }4. Pega o DANFE / QR-code
Quando status === 'authorized':
- DANFE PDF:
GET /v1/nfce/:id/danfe.pdf - XML assinado:
GET /v1/nfce/:id/xml - QR-code URL: já vem no campo
qrcode_urlda resposta acima.
Erros mais comuns no sandbox
| Status HTTP | Causa provável | Como resolver |
|---|---|---|
401 | API key faltando ou errada | Use Authorization: Bearer fk_sandbox_public |
422 | Item sem NCM ou CFOP | NCM obrigatório (21069090 p.ex.), CFOP varejo é 5102 |
429 | Rate limit sandbox (60req/min/IP) | Aguarde 60s. Em prod, rate-limit é por API key (configurável) |
409 idempotency_conflict | Mesmo Idempotency-Key com body diferente | Use chave nova ou mantenha body idêntico |
E agora?
- Webhooks — pra produção, abandone polling
- Idempotency-Key Stripe-style — o que evita emissão dupla
- SDK TypeScript — types autogerados do
/docs/json - NF-e modelo 55 (B2B) — diferenças vs NFC-e
⚠️
Sandbox reseta o DB às 04:00 UTC todo dia. Não dependa de IDs persistentes — é pra exploração.