Pular para conteúdo

Faturamento e DANFE

O Gubee tem dois serviços de nota fiscal com propósitos distintos. Antes de qualquer integração, é crítico entender qual usar:

Serviço Path Quando usar
/integration/invoices/* (legacy) /integration/invoices/* Apenas listar e baixar DANFEs já existentes. Não emite NF.
/integration/invoicer/invoices/* (recomendado) /integration/invoicer/invoices/* Emissão completa: sale, reversal, devolution, complementary, correction letter, cancel, preview-danfe.

A regra prática: se você precisa emitir NF, use /invoicer/invoices/*. O serviço legacy /invoices/* é apenas leitura e está mantido para compatibilidade com integrações antigas.

Para geração de etiquetas de envio (PLP/carrier label), veja Etiquetas de envio — é um fluxo separado da NF.

Pré-requisitos

  • Pedido em status PAID (veja Receber pedidos).
  • Emissor (empresa) configurado no painel Gubee com certificado digital válido.
  • Série e número de NF reservados para o canal.

Fluxo principal — emitir NF de saída (sale)

PAID ──► POST /invoicer/invoices/sale
         │  retorna invoiceId (status: PENDING)
         GET /invoicer/invoices/{id}  ──► status: AUTHORIZED
         PUT /integration/orders/invoiced/{orderId}  (com key/number da NF)
         INVOICED

Passo 1 — Criar a NF de venda

POST /integration/invoicer/invoices/sale

curl -X POST 'https://api.gubee.com.br/integration/invoicer/invoices/sale' \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "orderId": "MLB1234567890",
    "platform": "MERCADO_LIVRE",
    "accountId": "acct-seller-a",
    "items": [
      {
        "skuId": "sku-uuid-1001-blk",
        "externalId": "PHONE-1001-BLK",
        "qty": 1,
        "originalPrice": 4999.90,
        "salePrice": 4999.90,
        "discount": { "value": 0.00, "percentage": 0.0 },
        "subItems": [],
        "fulfillment": false
      }
    ],
    "total": 4999.90,
    "customer": {
      "name": "Maria Silva",
      "recipientName": "Maria Silva",
      "receiverName": "Maria Silva",
      "email": "maria.silva@example.com",
      "address": {
        "street": "Avenida Paulista",
        "number": "1578",
        "complement": "Apto 123",
        "district": "Bela Vista",
        "city": "São Paulo",
        "state": "SP",
        "zipCode": "01310-200",
        "country": "Brasil"
      },
      "documents": [{ "type": "CPF", "value": "12345678900" }],
      "phones": [{ "type": "MOBILE", "number": "11987654321", "countryCode": "55" }]
    },
    "discount": 0.00,
    "bills": [
      { "dueDate": "2026-08-07", "value": 4999.90, "number": 1 }
    ],
    "totalFreight": 0.00
  }'

Response 200

text/plain — o invoiceId interno:

60f8a5c2e3b2a87654321098

Passo 2 — Aguardar autorização

A NF entra em processamento na SEFAZ. Faça polling até status: AUTHORIZED:

curl 'https://api.gubee.com.br/integration/invoicer/invoices/60f8a5c2e3b2a87654321098' \
  -H 'Authorization: Bearer $TOKEN'

Response — NF autorizada

{
  "id": "60f8a5c2e3b2a87654321098",
  "sellerId": "SELLER123",
  "storeId": "60d8a5c2e3b2a87654321100",
  "operationType": "SALE",
  "status": "AUTHORIZED",
  "type": "PRODUCT",
  "issuer": {
    "name": "Empresa Exemplo Ltda",
    "document": "12345678901234",
    "address": {
      "street": "Rua Exemplo", "number": "123",
      "district": "Centro", "city": "São Paulo",
      "state": "SP", "zipCode": "01234-567", "country": "Brasil"
    }
  },
  "series": 1,
  "number": 123456,
  "key": "NFe35260707891234000111150010000012341123456789",
  "purpose": "NORMAL",
  "orderId": "MLB1234567890",
  "buyerPresence": "PRESENT",
  "externalId": "EXT123456",
  "reversed": false,
  "customer": { "...": "..." },
  "bills": [{ "dueDate": "2026-08-07", "value": 4999.90, "number": 1 }],
  "taxes": {
    "icmsValue": 850.78,
    "ipiValue": 0.0,
    "pisValue": 82.49,
    "cofinsValue": 380.04
  },
  "items": [ { "...": "..." } ],
  "createdDt": "2026-07-07T10:35:00Z"
}

Atalho: forçar autorização

Se a NF estiver em PENDING por tempo anormal, você pode disparar o processamento explicitamente:

curl 'https://api.gubee.com.br/integration/invoicer/invoices/authorize/60f8a5c2e3b2a87654321098' \
  -H 'Authorization: Bearer $TOKEN'

Retorna 200 sem body. O status continua em PENDING até a SEFAZ responder; faça polling.

Passo 3 — Anexar a NF ao pedido

Com a NF autorizada (e o key em mãos), avance o pedido para INVOICED:

curl -X PUT 'https://api.gubee.com.br/integration/orders/invoiced/MLB1234567890' \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "line": "NFe",
    "issueDate": "2026-07-07T12:00:00",
    "key": "NFe35260707891234000111150010000012341123456789",
    "number": "123456",
    "danfeLink": "https://storage.gubee.com.br/danfe/MLB1234567890.pdf"
  }'

Veja Receber pedidos para detalhes do endpoint.

Operações de NF

Devolução — POST /integration/invoicer/invoices/devolution

NF de entrada referenciando uma NF de saída (cliente devolveu produto).

curl -X POST 'https://api.gubee.com.br/integration/invoicer/invoices/devolution' \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "invoiceId": "60f8a5c2e3b2a87654321098",
    "items": [
      {
        "code": "PHONE-1001-BLK",
        "description": "Samsung Galaxy S24 256GB Preto",
        "ncm": "85171231",
        "cst": 0,
        "cfop": "1202",
        "unit": "UN",
        "quantity": 1.0,
        "unitPrice": 4999.90,
        "totalPrice": 4999.90,
        "icmsBaseCalculation": 4999.90,
        "icmsValue": 850.78,
        "icmsPercentage": 17.0,
        "origin": "NATIONAL"
      }
    ],
    "taxes": {
      "icmsValue": 850.78,
      "ipiValue": 0.0,
      "pisValue": 82.49,
      "cofinsValue": 380.04
    }
  }'

CFOP para devolução de venda interna: 1202 (comercial) ou 2202 (industrial). Para fora do estado, prefixar com 2. Veja tabela CFOP vigente.

Reversal (estorno) — POST /integration/invoicer/invoices/reversal

Usado quando a NF foi emitida indevidamente e ainda não transitou a mercadoria. Cria uma NF de estorno referenciando a original.

curl -X POST 'https://api.gubee.com.br/integration/invoicer/invoices/reversal' \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "invoiceId": "60f8a5c2e3b2a87654321098",
    "justification": "Estorno devido a itens incorretos na nota fiscal"
  }'

Complementar — POST /integration/invoicer/invoices/complementary

Quando a NF original foi emitida com valor menor que o devido (ex.: frete não foi cobrado).

curl -X POST 'https://api.gubee.com.br/integration/invoicer/invoices/complementary' \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "invoiceId": "60f8a5c2e3b2a87654321098",
    "items": [
      { "skuId": "sku-uuid-1001-blk", "quantity": 1, "price": 50.00 }
    ],
    "justification": "Nota fiscal complementar para cobrança adicional de frete"
  }'

Cancelar — DELETE /integration/invoicer/invoices/cancel-invoice/{id}

NF precisa estar dentro do prazo legal de cancelamento (geralmente 24h após autorização, varia por UF).

curl -X DELETE 'https://api.gubee.com.br/integration/invoicer/invoices/cancel-invoice/60f8a5c2e3b2a87654321098' \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: text/plain' \
  -d 'Nota fiscal cancelada a pedido do cliente devido a desistência da compra'

Body é text/plain contendo a justificativa (mínimo 15 caracteres).

Carta de correção — POST /integration/invoicer/invoices/correction-letter/{id}

Corrige dados menores (endereço, complemento, etc.) sem cancelar a NF. Limite legal: até 1 carta por evento, sem limite total.

curl -X POST 'https://api.gubee.com.br/integration/invoicer/invoices/correction-letter/60f8a5c2e3b2a87654321098' \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: text/plain' \
  -d 'Correção de dados do destinatário: CNPJ correto é 12.345.678/0001-99, Razão Social: Empresa Exemplo Ltda.'

Baixar PDF/XML da carta:

# PDF
curl 'https://api.gubee.com.br/integration/invoicer/invoices/download/correction-letter/60f8a5c2e3b2a87654321098?type=PDF' \
  -H 'Authorization: Bearer $TOKEN' \
  -o carta-correcao.pdf

# XML
curl 'https://api.gubee.com.br/integration/invoicer/invoices/download/correction-letter/60f8a5c2e3b2a87654321098?type=XML' \
  -H 'Authorization: Bearer $TOKEN' \
  -o carta-correcao.xml

FileType aceita PDF ou XML.

DANFE

Download da URL da DANFE

curl 'https://api.gubee.com.br/integration/invoicer/invoices/download/danfe/path/60f8a5c2e3b2a87654321098' \
  -H 'Authorization: Bearer $TOKEN'

Response (text/plain):

https://storage.gubee.com.br/danfe/60f8a5c2e3b2a87654321098.pdf

URL é pré-assinada com expiração de ~1h. Renove chamando novamente.

Preview de DANFE (antes de emitir)

Gera um PDF preview de como ficaria a DANFE sem autorizar a NF — útil para revisão antes do commit fiscal.

curl -X POST 'https://api.gubee.com.br/integration/invoicer/invoices/preview-danfe' \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/pdf' \
  -d '{
    "orderId": "MLB1234567890",
    "items": [ { "skuId": "sku-uuid-1001-blk", "quantity": 1, "price": 4999.90 } ],
    "customer": { "name": "Maria Silva", "...": "..." },
    "shippingAddress": { "...": "..." }
  }' \
  -o preview-danfe.pdf

Retorna binário application/pdf (não JSON).

Endpoint legacy — /integration/invoices/*

Para listagens simples e URL de download de NFs criadas por outros fluxos (marketplace, painel):

# Listar todas as NFs de um pedido
curl 'https://api.gubee.com.br/integration/invoices/list/MLB1234567890' \
  -H 'Authorization: Bearer $TOKEN'

# URL de download de uma NF específica
curl 'https://api.gubee.com.br/integration/invoices/download/{invoiceId}' \
  -H 'Authorization: Bearer $TOKEN'

Apenas leitura. Não emite nem atualiza NFs.

Consultas avançadas

Por sellerId (paginado)

curl -X POST 'https://api.gubee.com.br/integration/invoicer/invoices/by-seller-id' \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "sellerId": "SELLER123",
    "page": 0,
    "size": 20
  }'

Retorna FindInvoiceResponse com invoices[] e total.

Com filtros (número, data)

curl -X POST 'https://api.gubee.com.br/integration/invoicer/invoices/filtered' \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "sellerId": "SELLER123",
    "invoiceNumber": "123456",
    "startDate": "2026-07-01",
    "endDate": "2026-07-31",
    "page": 0,
    "size": 20
  }'

Forçar faturamento do pedido a partir da NF

Atalho que une os passos 2 e 3:

curl 'https://api.gubee.com.br/integration/invoicer/invoices/invoice-order/60f8a5c2e3b2a87654321098' \
  -H 'Authorization: Bearer $TOKEN'

Faz o backend atualizar o pedido para INVOICED usando os dados da NF. Útil quando a NF foi criada mas o pedido não foi atualizado por erro de rede.

Status de NF

Status Significado
PENDING Aguardando processamento na SEFAZ.
AUTHORIZED Autorizada na SEFAZ — válida.
CANCELED Cancelada (dentro do prazo legal).
REVERSED Estornada via reversal.
REJECTED Rejeitada pela SEFAZ (erro de schema, CFOP inválido, etc).
PROCESSING Em processamento interno.

Polling recomendado: a cada 5-10s até terminal (AUTHORIZED, REJECTED, CANCELED). Timeout máximo: 5 minutos.

Tratamento de erros

Status Causa Ação
400 Pedido não existe ou NF referenciada não existe Verifique IDs.
400 Schema NF inválido (CFOP, NCM, CST inexistentes) Corrija o payload com base na mensagem.
409 NF já existe para esse orderId Use a NF existente — faça GET /by-seller-id.
422 Voucher/fiscal configuration inválida Revise configuração fiscal no painel.
5xx SEFAZ indisponível ou timeout Backoff exponencial (até 5 retries).

Exemplo de erro 400 (rejeição SEFAZ)

{
  "type": "https://api.gubee.com.br/errors/sefaz-rejection",
  "title": "SEFAZ rejected the invoice",
  "status": 400,
  "detail": "Rejection code XREJ902: CFOP 5102 incompatível com CFOP de entrada do destinatário",
  "instance": "/integration/invoicer/invoices/sale",
  "sefazCode": "XREJ902",
  "sefazMessage": "CFOP incompatível"
}

Use sefazCode para mapear mensagens específicas ao operador fiscal.

Padrão de integração ERP

def emit_invoice_for_order(order_id):
    # 1. Pega o pedido
    order = get_order(order_id)
    if order.status != "PAID":
        raise InvalidStateError(f"order is {order.status}, must be PAID")

    # 2. Cria NF no invoicer
    invoice_id = post_invoicer_sale(build_sale_payload(order))

    # 3. Polling de autorização (max 5 min)
    for _ in range(60):
        invoice = get_invoicer_invoice(invoice_id)
        if invoice.status == "AUTHORIZED":
            break
        elif invoice.status == "REJECTED":
            raise SefazError(invoice.rejection_reason)
        sleep(5)
    else:
        raise TimeoutError("NF authorization timed out")

    # 4. Anexa ao pedido
    put_order_invoiced(order_id, build_invoice_payload(invoice))

    # 5. Próximo passo (gerar etiqueta) — ver tags.md
    return invoice

Próximos passos