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.
44 dígitos
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)
Configure no MD2 Router: http://sua-api.com.br/xmlnfe/
Opção 2: Query String
Configure no MD2 Router: http://sua-api.com.br/xml.php?chave=
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 |
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 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 |
5 Exemplos de Implementação
<?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'];
?>
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');
});
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)
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:
- Acesse Configurações → Empresa
- Localize o campo "Endpoint de Busca de XML"
-
Preencha com a URL do seu endpoint (escolha o formato):
Path Parameter:
http://sua-api.com.br/xmlnfe/Query String:A chave de acesso (44 dígitos) será anexada automaticamente ao final da URLhttp://sua-api.com.br/xml.php?chave= - Salve as configurações
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.