Documentação de Integração

Integração XML de NF-e

Configure seu próprio endpoint para que o MD2 Router importe automaticamente os XMLs de NF-e do seu sistema. Siga este guia passo a passo para criar sua integração.

Visão Geral do Fluxo

O MD2 Router consulta seu endpoint enviando a chave de acesso de 44 dígitos da NF-e. Seu sistema deve retornar o XML completo da nota fiscal.

MD2 Router
Envia Chave
44 dígitos
Seu Endpoint
Retorna XML

1 Especificação do Endpoint

Formatos Aceitos

O MD2 Router aceita dois formatos de endpoint. Escolha o que melhor se adapta ao seu sistema:

Opção 1: Path Parameter (Recomendado)

GET http://sua-api.com.br/xmlnfe/{chave}

Configure no MD2 Router: http://sua-api.com.br/xmlnfe/

Opção 2: Query String

GET http://sua-api.com.br/xml.php?chave={chave}

Configure no MD2 Router: http://sua-api.com.br/xml.php?chave=

Como funciona: O MD2 Router anexa automaticamente a chave de acesso (44 dígitos) ao final da URL configurada. Escolha o formato compatível com seu sistema.

Parâmetros

Parâmetro Tipo Descrição Exemplo
chave * String Chave de acesso da NF-e (44 dígitos numéricos) 35241012345678000195550010000001231123456789

2 Headers da Requisição

O MD2 Router enviará os seguintes headers na requisição ao seu endpoint:

Header Valor Descrição
Accept application/xml Indica que espera receber XML como resposta
User-Agent MD2Router/1.0 Identificação do MD2 Router
Segurança: O MD2 Router valida o JWT do usuário antes de fazer a consulta ao seu endpoint. Apenas usuários autenticados da empresa podem utilizar a integração.

3 Formato da Resposta

Resposta de Sucesso (HTTP 200)

Retorne o XML completo da NF-e no corpo da resposta com o header Content-Type: application/xml

XML de Resposta (exemplo)
<?xml version="1.0" encoding="UTF-8"?>
<nfeProc xmlns="http://www.portalfiscal.inf.br/nfe" versao="4.00">
  <NFe xmlns="http://www.portalfiscal.inf.br/nfe">
    <infNFe Id="NFe35241012345678000195550010000001231123456789" versao="4.00">
      <ide>
        <cUF>35</cUF>
        <cNF>12345678</cNF>
        <natOp>VENDA</natOp>
        <mod>55</mod>
        <serie>1</serie>
        <nNF>123</nNF>
        <dhEmi>2024-12-27T10:00:00-03:00</dhEmi>
        <tpNF>1</tpNF>
        <!-- ... outros campos ... -->
      </ide>
      <emit>
        <CNPJ>12345678000195</CNPJ>
        <xNome>EMPRESA EMITENTE LTDA</xNome>
        <enderEmit>
          <xLgr>RUA EXEMPLO</xLgr>
          <nro>100</nro>
          <xBairro>CENTRO</xBairro>
          <cMun>3550308</cMun>
          <xMun>SAO PAULO</xMun>
          <UF>SP</UF>
          <CEP>01310100</CEP>
        </enderEmit>
      </emit>
      <dest>
        <CNPJ>98765432000199</CNPJ>
        <xNome>CLIENTE DESTINATÁRIO LTDA</xNome>
        <enderDest>
          <xLgr>AV PAULISTA</xLgr>
          <nro>1000</nro>
          <xBairro>BELA VISTA</xBairro>
          <cMun>3550308</cMun>
          <xMun>SAO PAULO</xMun>
          <UF>SP</UF>
          <CEP>01310200</CEP>
        </enderDest>
      </dest>
      <det nItem="1">
        <prod>
          <cProd>001</cProd>
          <xProd>PRODUTO EXEMPLO</xProd>
          <qCom>10.0000</qCom>
          <vUnCom>100.00</vUnCom>
          <vProd>1000.00</vProd>
        </prod>
      </det>
      <total>
        <ICMSTot>
          <vNF>1000.00</vNF>
        </ICMSTot>
      </total>
      <transp>
        <vol>
          <qVol>5</qVol>
          <pesoL>25.500</pesoL>
          <pesoB>26.000</pesoB>
        </vol>
      </transp>
    </infNFe>
  </NFe>
  <protNFe versao="4.00">
    <infProt>
      <chNFe>35241012345678000195550010000001231123456789</chNFe>
      <dhRecbto>2024-12-27T10:05:00-03:00</dhRecbto>
      <nProt>135240000000001</nProt>
      <cStat>100</cStat>
      <xMotivo>Autorizado o uso da NF-e</xMotivo>
    </infProt>
  </protNFe>
</nfeProc>

Respostas de Erro

HTTP Code Situação Descrição
400 Bad Request Chave de acesso inválida (não tem 44 dígitos)
401 Unauthorized Credenciais de autenticação inválidas
404 Not Found NF-e não encontrada com a chave informada
500 Server Error Erro interno no servidor

4 Campos Utilizados pelo MD2 Router

O MD2 Router extrai as seguintes informações do XML para criar as rotas de entrega:

Campo XML Caminho (XPath) Uso no Sistema
chNFe //infProt/chNFe Identificação única da NF-e
nNF //ide/nNF Número da nota fiscal
dhEmi //ide/dhEmi Data de emissão
CNPJ (emit) //emit/CNPJ CNPJ do emitente (loja)
xNome (emit) //emit/xNome Nome do emitente
CNPJ/CPF (dest) //dest/CNPJ ou //dest/CPF Documento do destinatário
xNome (dest) //dest/xNome Nome do cliente
enderDest //dest/enderDest/* Endereço de entrega (xLgr, nro, xBairro, xMun, UF, CEP)
vNF //total/ICMSTot/vNF Valor total da NF
pesoL / pesoB //transp/vol/pesoL ou pesoB Peso da mercadoria
qVol //transp/vol/qVol Quantidade de volumes
Dica: O endereço do destinatário é geocodificado automaticamente para obter as coordenadas (latitude/longitude) usadas na roteirização.

5 Exemplos de Implementação

PHP - endpoint.php
<?php
// Configuração do CORS
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, OPTIONS");

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    exit(0);
}

// Extrair chave de acesso da URL
$uri = $_SERVER['REQUEST_URI'];
$partes = explode('/', trim($uri, '/'));
$chave = end($partes);

// Validar chave (44 dígitos)
$chave = preg_replace('/\D/', '', $chave);
if (strlen($chave) !== 44) {
    http_response_code(400);
    echo json_encode(["erro" => "Chave deve ter 44 dígitos"]);
    exit;
}

// Buscar XML no seu banco de dados
$pdo = new PDO('mysql:host=localhost;dbname=seu_banco', 'user', 'pass');
$stmt = $pdo->prepare("SELECT xml_content FROM notas_fiscais WHERE chave_acesso = ?");
$stmt->execute([$chave]);
$resultado = $stmt->fetch(PDO::FETCH_ASSOC);

if (!$resultado) {
    http_response_code(404);
    echo json_encode(["erro" => "NF-e não encontrada"]);
    exit;
}

// Retornar XML
header("Content-Type: application/xml; charset=utf-8");
echo $resultado['xml_content'];
?>
Node.js - server.js
const express = require('express');
const cors = require('cors');
const app = express();

app.use(cors());

// Endpoint de consulta XML
app.get('/xmlnfe/:chave', async (req, res) => {
    const { chave } = req.params;
    
    // Validar chave (44 dígitos)
    const chaveNumerica = chave.replace(/\D/g, '');
    if (chaveNumerica.length !== 44) {
        return res.status(400).json({ erro: 'Chave deve ter 44 dígitos' });
    }
    
    try {
        // Buscar XML no seu banco de dados
        const xml = await buscarXmlPorChave(chaveNumerica);
        
        if (!xml) {
            return res.status(404).json({ erro: 'NF-e não encontrada' });
        }
        
        res.set('Content-Type', 'application/xml');
        res.send(xml);
    } catch (error) {
        console.error(error);
        res.status(500).json({ erro: 'Erro interno' });
    }
});

// Função exemplo de busca no banco
async function buscarXmlPorChave(chave) {
    // Implemente sua lógica de banco de dados aqui
    // Exemplo com MySQL:
    // const [rows] = await pool.query(
    //     'SELECT xml_content FROM notas_fiscais WHERE chave_acesso = ?',
    //     [chave]
    // );
    // return rows[0]?.xml_content;
}

app.listen(3000, () => {
    console.log('API rodando na porta 3000');
});
Python - app.py (Flask)
from flask import Flask, Response, jsonify
from flask_cors import CORS
import re

app = Flask(__name__)
CORS(app)

@app.route('/xmlnfe/<chave>', methods=['GET'])
def get_xml_nfe(chave):
    # Validar chave (44 dígitos)
    chave_numerica = re.sub(r'\D', '', chave)
    if len(chave_numerica) != 44:
        return jsonify({"erro": "Chave deve ter 44 dígitos"}), 400
    
    # Buscar XML no banco de dados
    xml_content = buscar_xml_por_chave(chave_numerica)
    
    if not xml_content:
        return jsonify({"erro": "NF-e não encontrada"}), 404
    
    return Response(xml_content, mimetype='application/xml')

def buscar_xml_por_chave(chave):
    """Busca o XML no banco de dados"""
    # Implemente sua lógica de banco de dados aqui
    # Exemplo:
    # cursor.execute("SELECT xml_content FROM notas_fiscais WHERE chave_acesso = %s", (chave,))
    # result = cursor.fetchone()
    # return result['xml_content'] if result else None
    pass

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
C# - XmlNfeController.cs (ASP.NET Core)
using Microsoft.AspNetCore.Mvc;
using System.Text;
using System.Text.RegularExpressions;

[ApiController]
[Route("xmlnfe")]
public class XmlNfeController : ControllerBase
{
    private readonly IXmlRepository _xmlRepository;

    public XmlNfeController(IXmlRepository xmlRepository)
    {
        _xmlRepository = xmlRepository;
    }

    [HttpGet("{chave}")]
    public async Task<IActionResult> GetXml(string chave)
    {
        // Validar chave (44 dígitos)
        var chaveNumerica = Regex.Replace(chave, @"\D", "");
        if (chaveNumerica.Length != 44)
        {
            return BadRequest(new { erro = "Chave deve ter 44 dígitos" });
        }

        // Buscar XML
        var xml = await _xmlRepository.BuscarPorChaveAsync(chaveNumerica);
        
        if (string.IsNullOrEmpty(xml))
        {
            return NotFound(new { erro = "NF-e não encontrada" });
        }

        return Content(xml, "application/xml", Encoding.UTF8);
    }
}

6 Configuração no MD2 Router

Após criar seu endpoint, configure-o no cadastro da empresa no MD2 Router:

  1. Acesse Configurações → Empresa
  2. Localize o campo "Endpoint de Busca de XML"
  3. Preencha com a URL do seu endpoint (escolha o formato):
    Path Parameter: http://sua-api.com.br/xmlnfe/
    Query String: http://sua-api.com.br/xml.php?chave=
    A chave de acesso (44 dígitos) será anexada automaticamente ao final da URL
  4. Salve as configurações
Pronto! Após configurar, você poderá importar XMLs diretamente pela chave de acesso no MD2 Router. O sistema fará a consulta automaticamente ao seu endpoint.

Dúvidas Frequentes

Posso usar HTTPS com certificado autoassinado?

Recomendamos usar certificados válidos (Let's Encrypt é gratuito). Certificados autoassinados podem causar falhas na conexão.

Qual o timeout da requisição?

O MD2 Router aguarda até 30 segundos pela resposta. Garanta que seu endpoint responda dentro desse tempo.

O XML precisa estar assinado digitalmente?

Sim, o XML deve ser o mesmo que foi enviado para a SEFAZ, incluindo a assinatura digital e protocolo de autorização.