API — MeusPortais

Documentação da API REST para integração de NFS-e e CT-e

v1.0 Voltar ao sistema
Visão Geral

A API REST do MeusPortais permite que sistemas externos consultem as notas fiscais de serviços (NFS-e) sincronizadas, com as mesmas regras de acesso da interface web.

URL base:
https://baudenotas.com.br/api
Formato
  • Todas as requisições e respostas utilizam JSON
  • Datas de emissão no formato YYYY-MM-DD
  • Competência retornada no formato MM/YYYY
  • Valores numéricos como float (ex: 1500.00)
  • Campos ausentes retornam null
Cabeçalhos obrigatórios
CabeçalhoValorDescrição
Acceptapplication/jsonFormato esperado
Content-Typeapplication/jsonPara requisições com body
AuthorizationBearer {token}Rotas autenticadas
Autenticação

A API utiliza autenticação por token Bearer (Laravel Sanctum). O fluxo é:

  1. Faça uma requisição POST /api/auth/login com e-mail e senha
  2. Receba o token na resposta
  3. Inclua o token em todas as demais requisições via cabeçalho Authorization: Bearer {token}
  4. Ao finalizar, faça logout com POST /api/auth/logout para invalidar o token
Segurança: Cada novo login invalida o token anterior. Guarde o token em local seguro e nunca o exponha em logs ou código-fonte.
Permissões

As permissões da API seguem exatamente as mesmas regras da interface web:

PerfilAcesso
admin Vê todas as NFS-e de todas as filiais da empresa
user Vê apenas NFS-e das filiais explicitamente liberadas pelo administrador
Use GET /api/auth/me para verificar o perfil e as filiais do usuário autenticado.
Códigos de Erro
Código HTTPSignificado
200Sucesso
401Não autenticado — credenciais inválidas ou token ausente/expirado
403Sem permissão para o recurso solicitado
404Recurso não encontrado
422Erro de validação — verifique o campo errors na resposta
500Erro interno do servidor

Formato padrão de erro:

{
  "message": "Descrição do erro"
}

Para erros de validação (422):

{
  "message": "The given data was invalid.",
  "errors": {
    "email": ["O campo e-mail é obrigatório."]
  }
}
Endpoints de Autenticação
POST /api/auth/login
Autentica o usuário e retorna um token de acesso.
Body (JSON)
CampoTipoObrig.Descrição
emailstringSimE-mail do usuário
passwordstringSimSenha do usuário
REQUISIÇÃO
POST /api/auth/login
Content-Type: application/json

{
  "email": "usuario@empresa.com",
  "password": "minha-senha"
}
RESPOSTA 200
{
  "token": "1|abc123...",
  "token_type": "Bearer",
  "user": {
    "id": 1,
    "name": "João Silva",
    "email": "usuario@empresa.com",
    "role": "user"
  }
}
POST /api/auth/logout 🔒 Autenticado
Invalida o token atual do usuário.
REQUISIÇÃO
POST /api/auth/logout
Authorization: Bearer 1|abc123...
RESPOSTA 200
{
  "message": "Logout realizado com sucesso."
}
GET /api/auth/me 🔒 Autenticado
Retorna os dados do usuário autenticado e suas filiais de acesso.
REQUISIÇÃO
GET /api/auth/me
Authorization: Bearer 1|abc123...
RESPOSTA 200 (usuário)
{
  "id": 2,
  "name": "Maria Souza",
  "email": "maria@empresa.com",
  "role": "user",
  "filiais": [
    {
      "id": 1,
      "descricao": "Matriz SP",
      "cnpj": "12345678000195"
    }
  ]
}
Para usuários admin, o campo filiais retorna array vazio — eles têm acesso total a todas as filiais.
Endpoints de NFS-e
GET /api/nfse 🔒 Autenticado
Lista as NFS-e sincronizadas com suporte a filtros e paginação.
Parâmetros de Query
ParâmetroTipoPadrãoDescrição
pageinteger1Página atual
per_pageinteger25Registros por página (máx. 100)
order_bystringdata_emissaoCampo para ordenação: data_emissao, numero_nfse, competencia, valor_servicos, razao_social_prestador
order_dirstringdescasc ou desc
numerostringFiltra por número da NFS-e (parcial)
cnpj_prestadorstringFiltra por CNPJ do prestador (somente dígitos)
cnpj_filialstringFiltra por CNPJ da filial tomadora (somente dígitos)
prestadorstringFiltra por razão social do prestador (parcial)
competenciastringFiltra por competência no formato MM/YYYY
emissao_destringData de emissão inicial (YYYY-MM-DD)
emissao_atestringData de emissão final (YYYY-MM-DD)
chave_acessostringFiltra por chave de acesso (parcial)
statusstringnormal, cancelada ou vazio (todos)
REQUISIÇÃO
GET /api/nfse?page=1&per_page=10
  &emissao_de=2025-01-01
  &emissao_ate=2025-12-31
  &status=normal
Authorization: Bearer 1|abc123...
RESPOSTA 200
{
  "data": [
    {
      "id": 42,
      "nsu": "000000100042",
      "chave_acesso": "3525...",
      "data_emissao": "2025-03-15",
      "numero_nfse": "000000042",
      "serie": "001",
      "cnpj_filial": "12345678000195",
      "nome_filial": "Matriz SP",
      "cnpj_prestador": "98765432000188",
      "razao_social_prestador": "Fornecedor Ltda",
      "cnpj_tomador": "12345678000195",
      "razao_social_tomador": "Minha Empresa SA",
      "competencia": "03/2025",
      "valor_servicos": 1500.00,
      "valor_iss": 75.00,
      "aliquota": 5.0000,
      "iss_retido": false,
      "discriminacao": "Serviços de TI...",
      "codigo_municipio": "3550308",
      "item_lista_servico": "01.01",
      "status": "normal",
      "data_hora_geracao": "2025-03-15T10:30:00"
    }
  ],
  "meta": {
    "total": 1,
    "per_page": 10,
    "current_page": 1,
    "last_page": 1
  }
}
GET /api/nfse/{id} 🔒 Autenticado
Retorna os detalhes completos de uma NFS-e. Suporta inclusão de PDF (base64) e XML (base64) via query string.
Parâmetros
ParâmetroTipoPadrãoDescrição
idintegerID interno da NFS-e (campo id do resultado da listagem)
include_pdfbooleanfalseSe 1, inclui o DANFSe em PDF codificado em Base64 no campo pdf_base64
include_xmlbooleanfalseSe 1, inclui o XML original codificado em Base64 no campo xml_base64
REQUISIÇÃO (com PDF e XML)
GET /api/nfse/42?include_pdf=1&include_xml=1
Authorization: Bearer 1|abc123...
RESPOSTA 200
{
  "id": 42,
  "nsu": "000000100042",
  "chave_acesso": "3525...",
  "data_emissao": "2025-03-15",
  "numero_nfse": "000000042",
  "serie": "001",
  "cnpj_filial": "12345678000195",
  "nome_filial": "Matriz SP",
  "cnpj_prestador": "98765432000188",
  "razao_social_prestador": "Fornecedor Ltda",
  "cnpj_tomador": "12345678000195",
  "razao_social_tomador": "Minha Empresa SA",
  "competencia": "03/2025",
  "valor_servicos": 1500.00,
  "valor_iss": 75.00,
  "aliquota": 5.0000,
  "iss_retido": false,
  "discriminacao": "Serviços de TI...",
  "codigo_municipio": "3550308",
  "item_lista_servico": "01.01",
  "status": "normal",
  "lancada": false,
  "lancada_em": null,
  "lancada_por": null,
  "data_hora_geracao": "2025-03-15T10:30:00",
  "xml_base64": "PD94bWwgdmVyc2lvbj...",
  "pdf_base64": "JVBERi0xLjQKMSAw..."
}
Retorna 404 se a NFS-e não existir ou se o usuário não tiver permissão para a filial correspondente.
Omita include_pdf e include_xml quando não precisar destes dados para evitar resposta grande. Os campos retornam null quando não solicitados.
POST /api/nfse/{id}/lancada 🔒 Autenticado
Marca ou desmarca uma NFS-e como lançada no sistema externo. Registra o usuário e o horário da marcação.
Body (JSON)
CampoTipoObrig.Descrição
lancadabooleanSimtrue para marcar como lançada / false para remover a marcação
REQUISIÇÃO
POST /api/nfse/42/lancada
Authorization: Bearer 1|abc123...
Content-Type: application/json

{"lancada": true}
RESPOSTA 200
{
  "id": 42,
  "lancada": true,
  "lancada_em": "2025-03-15T14:22:00+00:00",
  "lancada_por": "João Silva <j@emp.com>",
  "message": "NFS-e marcada como lançada."
}
Endpoints de NF-e
GET /api/nfe
Lista os resumos de NF-e sincronizados com suporte a filtros e paginação.

Parâmetros de query:

ParâmetroTipoPadrãoDescrição
pageinteger1Página atual
per_pageinteger25Registros por página (máx. 100)
order_bystringdata_emissaoCampo para ordenação: data_emissao, numero_nfe, valor_nf, razao_emit
order_dirstringdescasc ou desc
chave_acessostringFiltra por chave de acesso (parcial, 44 dígitos)
numerostringFiltra por número da NF-e (parcial)
cnpj_emitentestringFiltra por CNPJ do emitente (somente números, parcial)
cnpj_filialstringFiltra por CNPJ da filial consultada (14 dígitos)
emitentestringFiltra por razão social do emitente (parcial)
tipo_nfinteger0 = Entrada, 1 = Saída
situacaostringautorizado, cancelado ou denegado
emissao_dedateData de emissão inicial (YYYY-MM-DD)
emissao_atedateData de emissão final (YYYY-MM-DD)
lancadabooleantrue / false — filtra por status de lançamento

Exemplo de requisição:

GET /api/nfe?page=1&per_page=10
Authorization: Bearer {token}

Exemplo de resposta:

{
  "data": [
    {
      "id": 1,
      "nsu": 500,
      "chave_acesso": "35250191154872000160550010000000071000000075",
      "data_emissao": "2025-03-10 08:30:00",
      "numero_nfe": "7",
      "serie": "1",
      "tipo_nf": 1,
      "tipo_nf_descricao": "Saída",
      "cnpj_filial": "91154872000160",
      "nome_filial": "Haenssgen",
      "cnpj_emitente": "91154872000160",
      "cpf_emitente": null,
      "razao_emitente": "Haenssgen Comércio Ltda",
      "ie_emitente": "1234567890",
      "cnpj_destinatario": "12345678000195",
      "cpf_destinatario": null,
      "razao_destinatario": null,
      "valor_nf": 1500.00,
      "situacao": "autorizado",
      "numero_protocolo": "135250000012345",
      "tipo_documento": "Resumo NF-e",
      "data_hora_geracao": "2025-03-10 08:31:00",
      "lancada": false,
      "lancada_em": null,
      "lancada_por": null
    }
  ],
  "meta": {
    "total": 1,
    "per_page": 10,
    "current_page": 1,
    "last_page": 1
  }
}
GET /api/nfe/{id}
Retorna os detalhes completos de uma NF-e, incluindo os eventos vinculados (cancelamentos, cartas de correção etc.).

Parâmetro de rota:

ParâmetroTipoDescrição
idintegerID interno da NF-e (campo id da listagem)

Exemplo de resposta:

GET /api/nfe/1
Authorization: Bearer {token}

{
  "id": 1,
  "nsu": 500,
  "chave_acesso": "35250191154872000160550010000000071000000075",
  "data_emissao": "2025-03-10 08:30:00",
  "numero_nfe": "7",
  "serie": "1",
  "tipo_nf": 1,
  "tipo_nf_descricao": "Saída",
  "cnpj_filial": "91154872000160",
  "nome_filial": "Haenssgen",
  "cnpj_emitente": "91154872000160",
  "cpf_emitente": null,
  "razao_emitente": "Haenssgen Comércio Ltda",
  "ie_emitente": "1234567890",
  "cnpj_destinatario": "12345678000195",
  "cpf_destinatario": null,
  "razao_destinatario": null,
  "valor_nf": 1500.00,
  "situacao": "autorizado",
  "numero_protocolo": "135250000012345",
  "tipo_documento": "Resumo NF-e",
  "data_hora_geracao": "2025-03-10 08:31:00",
  "lancada": false,
  "lancada_em": null,
  "lancada_por": null,
  "eventos": [
    {
      "nsu": 501,
      "tipo_evento": "Cancelamento",
      "data_hora_geracao": "2025-03-11 10:00:00"
    }
  ]
}
Retorna 404 se a NF-e não existir ou o usuário não tiver permissão para a filial.
POST /api/nfe/{id}/lancada
Marca ou desmarca uma NF-e como lançada no sistema externo. Registra o usuário e o horário da marcação.

Body (JSON):

CampoTipoObrigatórioDescrição
lancadabooleanSimtrue para marcar, false para desmarcar

Exemplo:

POST /api/nfe/1/lancada
Authorization: Bearer {token}
Content-Type: application/json

{"lancada": true}

// Resposta 200
{
  "id": 1,
  "lancada": true,
  "lancada_em": "2025-03-15T14:22:00+00:00",
  "lancada_por": "João Silva <j@emp.com>",
  "message": "NF-e marcada como lançada."
}
Endpoints de CT-e
GET /api/cte 🔒 Autenticado
Lista os CT-e sincronizados com suporte a filtros e paginação.
Parâmetros de Query
ParâmetroTipoPadrãoDescrição
pageinteger1Página atual
per_pageinteger25Registros por página (máx. 100)
order_bystringdata_emissaoCampo para ordenação: data_emissao, numero_cte, modal, valor_total_prestacao, razao_emit
order_dirstringdescasc ou desc
numerostringFiltra por número do CT-e (parcial)
chave_acessostringFiltra por chave de acesso (parcial)
cnpj_emitentestringFiltra por CNPJ da transportadora (somente dígitos)
cnpj_filialstringFiltra por CNPJ da filial tomadora (somente dígitos)
emitentestringFiltra por razão social da transportadora (parcial)
modalstringCódigo do modal: 01 Rodoviário, 02 Aéreo, 03 Aquaviário, 04 Ferroviário, 05 Dutoviário, 06 Multimodal
emissao_destringData de emissão inicial (YYYY-MM-DD)
emissao_atestringData de emissão final (YYYY-MM-DD)
statusstringnormal, cancelada ou vazio (todos)
lancadabooleantrue ou false para filtrar por status de lançamento
REQUISIÇÃO
GET /api/cte?page=1&per_page=10
  &emissao_de=2025-01-01
  &emissao_ate=2025-12-31
  &modal=01
Authorization: Bearer 1|abc123...
RESPOSTA 200
{
  "data": [
    {
      "id": 7,
      "nsu": "000000100007",
      "chave_acesso": "3525...",
      "data_emissao": "2025-03-10T00:00:00",
      "numero_cte": "000000007",
      "serie": "1",
      "cfop": "6352",
      "nat_op": "PRESTACAO DE SERVICO",
      "modal": "01",
      "modal_descricao": "Rodoviário",
      "cnpj_filial": "12345678000195",
      "nome_filial": "Matriz SP",
      "uf_ini": "SP",
      "uf_fim": "RJ",
      "cnpj_emitente": "11222333000181",
      "razao_emitente": "Transportes ABC Ltda",
      "cnpj_remetente": "12345678000195",
      "razao_remetente": "Minha Empresa SA",
      "cnpj_destinatario": "98765432000188",
      "razao_destinatario": "Cliente Final Ltda",
      "cnpj_tomador": "12345678000195",
      "razao_tomador": "Minha Empresa SA",
      "ind_tomador": 0,
      "valor_total_prestacao": 850.00,
      "valor_receber": 850.00,
      "produto_predominante": "Eletrônicos",
      "status": "normal",
      "data_hora_geracao": "2025-03-10T08:45:00",
      "lancada": false,
      "lancada_em": null,
      "lancada_por": null
    }
  ],
  "meta": {
    "total": 1,
    "per_page": 10,
    "current_page": 1,
    "last_page": 1
  }
}
O campo ind_tomador indica quem é o tomador do serviço: 0 = Remetente, 1 = Expedidor, 2 = Recebedor, 3 = Destinatário, 4 = Outros.
GET /api/cte/{id} 🔒 Autenticado
Retorna os detalhes completos de um CT-e. Suporta inclusão do XML (base64) via query string.
Parâmetros
ParâmetroTipoPadrãoDescrição
idintegerID interno do CT-e (campo id do resultado da listagem)
include_xmlbooleanfalseSe 1, inclui o XML original codificado em Base64 no campo xml_base64
REQUISIÇÃO
GET /api/cte/7?include_xml=1
Authorization: Bearer 1|abc123...
RESPOSTA 200
{
  "id": 7,
  "nsu": "000000100007",
  "chave_acesso": "3525...",
  "data_emissao": "2025-03-10T00:00:00",
  "numero_cte": "000000007",
  "serie": "1",
  "cfop": "6352",
  "nat_op": "PRESTACAO DE SERVICO",
  "modal": "01",
  "modal_descricao": "Rodoviário",
  "cnpj_filial": "12345678000195",
  "nome_filial": "Matriz SP",
  "uf_ini": "SP",
  "uf_fim": "RJ",
  "cnpj_emitente": "11222333000181",
  "razao_emitente": "Transportes ABC Ltda",
  "cnpj_remetente": "12345678000195",
  "cpf_remetente": null,
  "razao_remetente": "Minha Empresa SA",
  "cnpj_destinatario": "98765432000188",
  "cpf_destinatario": null,
  "razao_destinatario": "Cliente Final Ltda",
  "cnpj_tomador": "12345678000195",
  "cpf_tomador": null,
  "razao_tomador": "Minha Empresa SA",
  "ind_tomador": 0,
  "valor_total_prestacao": 850.00,
  "valor_receber": 850.00,
  "produto_predominante": "Eletrônicos",
  "status": "normal",
  "tipo_documento": "CT-e",
  "data_hora_geracao": "2025-03-10T08:45:00",
  "lancada": false,
  "lancada_em": null,
  "lancada_por": null,
  "xml_base64": "PD94bWwgdmVyc2lvbj..."
}
Retorna 404 se o CT-e não existir ou se o usuário não tiver permissão para a filial correspondente.
POST /api/cte/{id}/lancada 🔒 Autenticado
Marca ou desmarca um CT-e como lançado no sistema externo. Registra o usuário e o horário da marcação.
Body (JSON)
CampoTipoObrig.Descrição
lancadabooleanSimtrue para marcar como lançado / false para remover a marcação
REQUISIÇÃO
POST /api/cte/7/lancada
Authorization: Bearer 1|abc123...
Content-Type: application/json

{"lancada": true}
RESPOSTA 200
{
  "id": 7,
  "lancada": true,
  "lancada_em": "2025-03-15T14:22:00+00:00",
  "lancada_por": "João Silva <j@emp.com>",
  "message": "CT-e marcado como lançado."
}
Exemplos de Integração
cURL

1. Fazer login e obter token:

curl -s -X POST https://baudenotas.com.br/api/auth/login \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"email":"usuario@empresa.com","password":"senha123"}'

2. Listar NFS-e com filtro de período:

curl -s "https://baudenotas.com.br/api/nfse?emissao_de=2025-01-01&emissao_ate=2025-12-31&per_page=50" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer SEU_TOKEN_AQUI"

3. Buscar NFS-e específica (com XML):

curl -s "https://baudenotas.com.br/api/nfse/42?include_xml=1" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer SEU_TOKEN_AQUI"

4. Listar NF-e de entrada não lançadas:

curl -s "https://baudenotas.com.br/api/nfe?tipo_nf=0&lancada=false&per_page=50" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer SEU_TOKEN_AQUI"

5. Listar CT-e rodoviário não lançado:

curl -s "https://baudenotas.com.br/api/cte?modal=01&lancada=false&per_page=50" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer SEU_TOKEN_AQUI"

6. Marcar NF-e como lançada:

curl -s -X POST "https://baudenotas.com.br/api/nfe/1/lancada" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer SEU_TOKEN_AQUI" \
  -d '{"lancada": true}'

7. Marcar CT-e como lançado:

curl -s -X POST "https://baudenotas.com.br/api/cte/7/lancada" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer SEU_TOKEN_AQUI" \
  -d '{"lancada": true}'

8. Logout:

curl -s -X POST https://baudenotas.com.br/api/auth/logout \
  -H "Accept: application/json" \
  -H "Authorization: Bearer SEU_TOKEN_AQUI"
PHP
<?php
$base = 'https://baudenotas.com.br/api';

// 1. Login
$resp = file_get_contents($base . '/auth/login', false, stream_context_create([
    'http' => [
        'method'  => 'POST',
        'header'  => "Content-Type: application/json\r\nAccept: application/json\r\n",
        'content' => json_encode([
            'email'    => 'usuario@empresa.com',
            'password' => 'senha123',
        ]),
    ],
]));
$auth  = json_decode($resp, true);
$token = $auth['token'];

// 2. Listar NFS-e
$opts = stream_context_create([
    'http' => [
        'method' => 'GET',
        'header' => "Accept: application/json\r\nAuthorization: Bearer $token\r\n",
    ],
]);
$resp  = file_get_contents($base . '/nfse?per_page=50&status=normal', false, $opts);
$dados = json_decode($resp, true);

foreach ($dados['data'] as $nfse) {
    echo $nfse['numero_nfse'] . ' — ' . $nfse['razao_social_prestador'] . "\n";
}

// 3. Listar NF-e de entrada e marcar como lançada
$resp = file_get_contents($base . '/nfe?per_page=50&tipo_nf=0&lancada=false', false, $opts);
$nfes = json_decode($resp, true);

foreach ($nfes['data'] as $nfe) {
    echo $nfe['numero_nfe'] . ' — ' . $nfe['razao_emitente'] . ' R$ ' . $nfe['valor_nf'] . "\n";

    $ctx = stream_context_create([
        'http' => [
            'method'  => 'POST',
            'header'  => "Content-Type: application/json\r\nAccept: application/json\r\nAuthorization: Bearer $token\r\n",
            'content' => json_encode(['lancada' => true]),
        ],
    ]);
    file_get_contents($base . '/nfe/' . $nfe['id'] . '/lancada', false, $ctx);
}

// 4. Listar CT-e e marcar como lançado
$resp = file_get_contents($base . '/cte?per_page=50&lancada=false', false, $opts);
$ctes = json_decode($resp, true);

foreach ($ctes['data'] as $cte) {
    echo $cte['numero_cte'] . ' — ' . $cte['razao_emitente'] . "\n";

    $ctx = stream_context_create([
        'http' => [
            'method'  => 'POST',
            'header'  => "Content-Type: application/json\r\nAccept: application/json\r\nAuthorization: Bearer $token\r\n",
            'content' => json_encode(['lancada' => true]),
        ],
    ]);
    file_get_contents($base . '/cte/' . $cte['id'] . '/lancada', false, $ctx);
}

// 4. Logout
file_get_contents($base . '/auth/logout', false, stream_context_create([
    'http' => [
        'method' => 'POST',
        'header' => "Accept: application/json\r\nAuthorization: Bearer $token\r\n",
    ],
]));
Python (requests)
import requests

BASE = 'https://baudenotas.com.br/api'
session = requests.Session()
session.headers.update({'Accept': 'application/json'})

# 1. Login
resp = session.post(f'{BASE}/auth/login', json={
    'email': 'usuario@empresa.com',
    'password': 'senha123',
})
resp.raise_for_status()
token = resp.json()['token']
session.headers['Authorization'] = f'Bearer {token}'

# 2. Listar NFS-e com paginação automática
page = 1
while True:
    resp = session.get(f'{BASE}/nfse', params={
        'page': page, 'per_page': 100, 'status': 'normal',
        'emissao_de': '2025-01-01', 'emissao_ate': '2025-12-31',
    })
    dados = resp.json()
    for nfse in dados['data']:
        print(nfse['numero_nfse'], '-', nfse['razao_social_prestador'])

    if page >= dados['meta']['last_page']:
        break
    page += 1

# 3. Buscar NFS-e específica (com XML)
nfse = session.get(f'{BASE}/nfse/42', params={'include_xml': 1}).json()
print('Valor:', nfse['valor_servicos'])

# 4. Listar NF-e de entrada não lançadas e processar
page = 1
while True:
    resp = session.get(f'{BASE}/nfe', params={
        'page': page, 'per_page': 100, 'lancada': 'false',
        'tipo_nf': 0, 'emissao_de': '2025-01-01',
    })
    dados = resp.json()
    for nfe in dados['data']:
        print(nfe['numero_nfe'], '-', nfe['razao_emitente'], f"R$ {nfe['valor_nf']}")
        session.post(f"{BASE}/nfe/{nfe['id']}/lancada", json={'lancada': True})

    if page >= dados['meta']['last_page']:
        break
    page += 1

# 5. Listar CT-e não lançados e processar
page = 1
while True:
    resp = session.get(f'{BASE}/cte', params={
        'page': page, 'per_page': 100, 'lancada': 'false',
        'emissao_de': '2025-01-01',
    })
    dados = resp.json()
    for cte in dados['data']:
        print(cte['numero_cte'], '-', cte['razao_emitente'], f"R$ {cte['valor_total_prestacao']}")
        session.post(f"{BASE}/cte/{cte['id']}/lancada", json={'lancada': True})

    if page >= dados['meta']['last_page']:
        break
    page += 1

# 5. Logout
session.post(f'{BASE}/auth/logout')
ADVPL — Protheus (TOTVS)

Utilize a classe FWRest disponível no Protheus (LIB ≥ 20180101) para chamar a API. As credenciais e o endereço do servidor são lidos de parâmetros MV via SUPERGETMV(), mantendo o código limpo e sem dados sensíveis expostos.

Pré-requisito: Crie os parâmetros MPBASE, MPLOGIN e MPSENHA no configurador do Protheus (SIGACFG → Ambiente → Parâmetros) com a URL base da API e as credenciais de acesso.

Includes e definições:

#include 'protheus.ch'
#include 'restful.ch'

#define MP_BASE  SUPERGETMV("MPBASE" ,.F.,"")
#define MP_LOGIN SUPERGETMV("MPLOGIN",.F.,"")
#define MP_SENHA SUPERGETMV("MPSENHA",.F.,"")

1. Login — obter token:

/*
 * Autentica na MP e retorna o Bearer token.
 * Retorna "" em caso de falha.
 */
Static Function MPLogin()
    Local oRest   := FWRest():New(MP_BASE)
    Local cToken  := ""
    Local aHeader := {}
    Local cBody   := '{"email":"' + MP_LOGIN + '","password":"' + MP_SENHA + '"}'
    Local oJson

    aAdd(aHeader, 'Content-Type: application/json')
    aAdd(aHeader, 'User-Agent: TotvsProtheus ' + GetBuild())

    oRest:SetPath('/auth/login')
    oRest:SetPostParams(cBody)

    If oRest:POST(aHeader)
        oJson := JSonObject():New()
        oJson:FromJson(oRest:cResult)
        cToken := oJson["token"]
        FreeObj(oJson)
    Else
        Conout('Erro no login: ' + oRest:cResult, 'API NFS-e')
    EndIf

    FreeObj(oRest)
Return cToken

2. Listar NFS-e com filtros:

/*
 * Lista NFS-e. Retorna array de registros ou NIL em erro.
 * Parâmetros:
 *   dDe / dAte    - Datas de emissão (tipo Date) ou CtoD('') para sem filtro
 *   cStatus       - "normal", "cancelada" ou "" para todos
 *   nPage         - Página inicial (começa em 1)
 *   lTodas        - .T. para percorrer todas as páginas automaticamente
 *   cChave        - Chave de acesso (parcial ou completa)
 *   cCnpjPrest    - CNPJ do prestador (somente números)
 *   cNumeroNfse   - Número da NFS-e
 *
 * Retorno — cada elemento do array:
 *   [1]  ID          [2]  Número       [3]  Data emissão
 *   [4]  CNPJ Filial [5]  Nome Filial  [6]  CNPJ Prestador
 *   [7]  Prestador   [8]  Vl. Serviços [9]  Competência
 *   [10] Status      [11] Lançada?     [12] Chave Acesso
 *   [13] Cód. Serviço [14] Discriminação
 */
User Function MPListarNfse(dDe, dAte, cStatus, nPage, lTodas, cChave, cCnpjPrest, cNumeroNfse)
    Local oRest    := FWRest():New(MP_BASE)
    Local cToken   := MPLogin()
    Local aNotas   := {}
    Local aHeader  := {}
    Local oJson, oData, oMeta, i, oItem
    Local cDtS, cParams
    Local nCurPage  := If(nPage >= 1, nPage, 1)
    Local nLastPage := nCurPage

    If Empty(cToken)
        Return NIL
    EndIf

    If ValType(lTodas) != 'L'
        lTodas := .F.
    EndIf

    aAdd(aHeader, 'Content-Type: application/json')
    aAdd(aHeader, 'Authorization: Bearer ' + cToken)
    aAdd(aHeader, 'User-Agent: TotvsProtheus ' + GetBuild())

    Do While nCurPage <= nLastPage

        cParams := 'page=' + cValToChar(nCurPage) + '&per_page=100'

        If !Empty(dDe)
            cDtS    := DToS(dDe)
            cParams += '&emissao_de=' + SubStr(cDtS,1,4) + '-' + SubStr(cDtS,5,2) + '-' + SubStr(cDtS,7,2)
        EndIf
        If !Empty(dAte)
            cDtS    := DToS(dAte)
            cParams += '&emissao_ate=' + SubStr(cDtS,1,4) + '-' + SubStr(cDtS,5,2) + '-' + SubStr(cDtS,7,2)
        EndIf
        If !Empty(cStatus)
            cParams += '&status=' + cStatus
        EndIf
        If !Empty(cChave)
            cParams += '&chave_acesso=' + cChave
        EndIf
        If !Empty(cCnpjPrest)
            cParams += '&cnpj_prestador=' + cCnpjPrest
        EndIf
        If !Empty(cNumeroNfse)
            cParams += '&numero_nfse=' + cNumeroNfse
        EndIf

        oRest:SetPath('/nfse')
        oRest:SetGetParams(cParams)

        If oRest:GET(aHeader)
            oJson := JSonObject():New()
            oJson:FromJson(oRest:cResult)
            oData := oJson["data"]
            For i := 1 To Len(oData)
                oItem := oData[i]
                aAdd(aNotas, {;
                    oItem["id"],                     ; // [1]  ID
                    oItem["numero_nfse"],             ; // [2]  Número
                    oItem["data_emissao"],            ; // [3]  Data emissão
                    oItem["cnpj_filial"],             ; // [4]  CNPJ Filial
                    oItem["nome_filial"],             ; // [5]  Nome Filial
                    oItem["cnpj_prestador"],          ; // [6]  CNPJ Prestador
                    oItem["razao_social_prestador"],  ; // [7]  Prestador
                    oItem["valor_servicos"],          ; // [8]  Valor Serviços
                    oItem["competencia"],             ; // [9]  Competência
                    oItem["status"],                 ; // [10] Status
                    oItem["lancada"],                 ; // [11] Lançada?
                    oItem["chave_acesso"],            ; // [12] Chave Acesso
                    oItem["item_lista_servico"],      ; // [13] Cód. Serviço
                    oItem["discriminacao"]           ; // [14] Discriminação
                })
            Next i

            If lTodas
                oMeta     := oJson["meta"]
                nLastPage := oMeta["last_page"]
            EndIf

            FreeObj(oJson)
        Else
            Conout('Erro ao listar NFS-e: ' + oRest:cResult, 'API NFS-e')
            aNotas := NIL
            Exit
        EndIf

        nCurPage++

    EndDo

    FreeObj(oRest)
Return aNotas

3. Marcar / desmarcar NFS-e como lançada:

/*
 * Marca ou desmarca uma NFS-e como lançada no sistema.
 * Localiza a nota pela chave de acesso OU por CNPJ do prestador + número.
 *
 * Parâmetros:
 *   cChave      - Chave de acesso da nota (preferencial)
 *   lLancada    - .T. para marcar como lançada, .F. para desmarcar
 *   cCnpjPrest  - CNPJ do prestador (somente números) — alternativa à chave
 *   cNumeroNfse - Número da NFS-e — alternativa à chave
 *
 * Retorna .T. em caso de sucesso.
 */
User Function MPDemarcaLancada(cChave, lLancada, cCnpjPrest, cNumeroNfse)
    Local cToken  := MPLogin()
    Local aNotas  := {}
    Local cId     := ''
    Local oRest
    Local aHeader := {}
    Local cBody
    Local lOk     := .F.

    If Empty(cToken)
        Return lOk
    EndIf

    Default lLancada    := .T.
    Default cChave      := ''
    Default cCnpjPrest  := ''
    Default cNumeroNfse := ''

    If Empty(cChave) .And. (Empty(cCnpjPrest) .Or. Empty(cNumeroNfse))
        Conout('Informe a chave de acesso ou o CNPJ do prestador + numero da NFS-e.', 'API NFS-e')
        Return lOk
    EndIf

    // Localiza o ID da nota via listagem
    aNotas := U_MPListarNfse(CtoD(''), CtoD(''), '', 1, .F., cChave, cCnpjPrest, cNumeroNfse)

    If aNotas == NIL .Or. Len(aNotas) == 0
        Conout('NFS-e nao encontrada para os dados informados.', 'API NFS-e')
        Return lOk
    EndIf

    cId := cValToChar(aNotas[1][1])

    oRest := FWRest():New(MP_BASE)
    aAdd(aHeader, 'Content-Type: application/json')
    aAdd(aHeader, 'Authorization: Bearer ' + MPLogin())
    aAdd(aHeader, 'User-Agent: TotvsProtheus ' + GetBuild())

    cBody := '{"lancada":' + If(lLancada, 'true', 'false') + '}'

    oRest:SetPath('/nfse/' + cId + '/lancada')
    oRest:SetPostParams(cBody)

    If oRest:POST(aHeader)
        lOk := .T.
    Else
        Conout('Erro ao atualizar NFS-e: ' + oRest:cResult, 'API NFS-e')
    EndIf

    FreeObj(oRest)
Return lOk

4. Exemplo de uso completo:

/*
 * Exemplo: buscar todas as notas normais não lançadas
 * e marcar cada uma após processar no Protheus.
 * lTodas=.T. percorre todas as páginas automaticamente.
 */
User Function ImportaNFSe()
    Local aNotas  := U_MPListarNfse(CtoD(''), CtoD(''), 'normal', 1, .T., '', '', '')
    Local i, aItem

    If aNotas == NIL
        Conout('Falha ao obter notas.', 'API NFS-e')
        Return
    EndIf

    For i := 1 To Len(aNotas)
        aItem := aNotas[i]

        // [11] lancada — pula notas já lançadas
        If aItem[11]
            Loop
        EndIf

        // *** Insira aqui a lógica de lançamento no Protheus ***
        // Ex: GravarNotaFiscal(aItem)

        // Marca como lançada pela chave de acesso [12]
        If !Empty(aItem[12])
            U_MPDemarcaLancada(aItem[12], .T., '', '')
        EndIf

    Next i

    MsgInfo('Importacao concluida! ' + cValToChar(Len(aNotas)) + ' nota(s) processada(s).', 'API NFS-e')
Return
Dica: Use lTodas := .T. em U_MPListarNfse para percorrer automaticamente todas as páginas de resultados — ideal para integrações em batch. Para buscas pontuais passe .F. e controle a paginação manualmente via nPage.
ADVPL — Protheus (CT-e)

Funções equivalentes às de NFS-e, adaptadas para os campos do CT-e. Utilize os mesmos parâmetros MV (MPBASE, MPLOGIN, MPSENHA) e a função MPLogin() definida na seção anterior.

1. Listar CT-e com filtros:

/*
 * Lista CT-e. Retorna array de registros ou NIL em erro.
 * Parâmetros:
 *   dDe / dAte    - Datas de emissão (tipo Date) ou CtoD('') para sem filtro
 *   cStatus       - "normal", "cancelada" ou "" para todos
 *   nPage         - Página inicial (começa em 1)
 *   lTodas        - .T. para percorrer todas as páginas automaticamente
 *   cChave        - Chave de acesso (parcial ou completa)
 *   cCnpjEmit     - CNPJ da transportadora (somente números)
 *   cModal        - Código do modal: 01=Rod, 02=Aéreo, 03=Aqua, 04=Ferr, 05=Duto, 06=Multi
 *   lNaoLancados  - .T. para trazer apenas CT-e não lançados
 *
 * Retorno — cada elemento do array:
 *   [1]  ID               [2]  Número CT-e      [3]  Data emissão
 *   [4]  CNPJ Filial      [5]  Nome Filial       [6]  CNPJ Emitente
 *   [7]  Razão Emitente   [8]  Razão Remetente   [9]  Razão Destinatário
 *   [10] CFOP             [11] Modal             [12] Modal (descrição)
 *   [13] UF Ini           [14] UF Fim            [15] Valor Total Prestação
 *   [16] Valor a Receber  [17] Produto Predom.   [18] Status
 *   [19] Lançado?         [20] Chave Acesso      [21] CNPJ Tomador
 *   [22] Razão Tomador    [23] Ind. Tomador
 */
User Function MPListarCte(dDe, dAte, cStatus, nPage, lTodas, cChave, cCnpjEmit, cModal, lNaoLancados)
    Local oRest    := FWRest():New(MP_BASE)
    Local cToken   := MPLogin()
    Local aCtes    := {}
    Local aHeader  := {}
    Local oJson, oData, oMeta, i, oItem
    Local cDtS, cParams
    Local nCurPage  := If(nPage >= 1, nPage, 1)
    Local nLastPage := nCurPage

    If Empty(cToken)
        Return NIL
    EndIf

    If ValType(lTodas)      != 'L' ; lTodas      := .F. ; EndIf
    If ValType(lNaoLancados) != 'L'; lNaoLancados := .F. ; EndIf

    aAdd(aHeader, 'Content-Type: application/json')
    aAdd(aHeader, 'Authorization: Bearer ' + cToken)
    aAdd(aHeader, 'User-Agent: TotvsProtheus ' + GetBuild())

    Do While nCurPage <= nLastPage

        cParams := 'page=' + cValToChar(nCurPage) + '&per_page=100'

        If !Empty(dDe)
            cDtS    := DToS(dDe)
            cParams += '&emissao_de=' + SubStr(cDtS,1,4) + '-' + SubStr(cDtS,5,2) + '-' + SubStr(cDtS,7,2)
        EndIf
        If !Empty(dAte)
            cDtS    := DToS(dAte)
            cParams += '&emissao_ate=' + SubStr(cDtS,1,4) + '-' + SubStr(cDtS,5,2) + '-' + SubStr(cDtS,7,2)
        EndIf
        If !Empty(cStatus)
            cParams += '&status=' + cStatus
        EndIf
        If !Empty(cChave)
            cParams += '&chave_acesso=' + cChave
        EndIf
        If !Empty(cCnpjEmit)
            cParams += '&cnpj_emitente=' + cCnpjEmit
        EndIf
        If !Empty(cModal)
            cParams += '&modal=' + cModal
        EndIf
        If lNaoLancados
            cParams += '&lancada=false'
        EndIf

        oRest:SetPath('/cte')
        oRest:SetGetParams(cParams)

        If oRest:GET(aHeader)
            oJson := JSonObject():New()
            oJson:FromJson(oRest:cResult)
            oData := oJson["data"]
            For i := 1 To Len(oData)
                oItem := oData[i]
                aAdd(aCtes, {;
                    oItem["id"],                    ; // [1]  ID
                    oItem["numero_cte"],             ; // [2]  Número CT-e
                    oItem["data_emissao"],           ; // [3]  Data emissão
                    oItem["cnpj_filial"],            ; // [4]  CNPJ Filial
                    oItem["nome_filial"],            ; // [5]  Nome Filial
                    oItem["cnpj_emitente"],          ; // [6]  CNPJ Emitente
                    oItem["razao_emitente"],         ; // [7]  Razão Emitente
                    oItem["razao_remetente"],        ; // [8]  Razão Remetente
                    oItem["razao_destinatario"],     ; // [9]  Razão Destinatário
                    oItem["cfop"],                   ; // [10] CFOP
                    oItem["modal"],                  ; // [11] Modal (código)
                    oItem["modal_descricao"],        ; // [12] Modal (descrição)
                    oItem["uf_ini"],                 ; // [13] UF Início
                    oItem["uf_fim"],                 ; // [14] UF Fim
                    oItem["valor_total_prestacao"],  ; // [15] Valor Total Prestação
                    oItem["valor_receber"],          ; // [16] Valor a Receber
                    oItem["produto_predominante"],   ; // [17] Produto Predom.
                    oItem["status"],                 ; // [18] Status
                    oItem["lancada"],                ; // [19] Lançado?
                    oItem["chave_acesso"],           ; // [20] Chave Acesso
                    oItem["cnpj_tomador"],           ; // [21] CNPJ Tomador
                    oItem["razao_tomador"],          ; // [22] Razão Tomador
                    oItem["ind_tomador"]             ; // [23] Ind. Tomador
                })
            Next i

            If lTodas
                oMeta     := oJson["meta"]
                nLastPage := oMeta["last_page"]
            EndIf

            FreeObj(oJson)
        Else
            Conout('Erro ao listar CT-e: ' + oRest:cResult, 'API CT-e')
            aCtes := NIL
            Exit
        EndIf

        nCurPage++

    EndDo

    FreeObj(oRest)
Return aCtes

2. Marcar / desmarcar CT-e como lançado:

/*
 * Marca ou desmarca um CT-e como lançado.
 * Localiza pelo ID direto ou pela chave de acesso.
 *
 * Parâmetros:
 *   nId      - ID interno do CT-e (use 0 para localizar pela chave)
 *   lLancada - .T. para marcar, .F. para desmarcar
 *   cChave   - Chave de acesso (usada quando nId = 0)
 *
 * Retorna .T. em caso de sucesso.
 */
User Function MPDemarcaCte(nId, lLancada, cChave)
    Local cToken  := MPLogin()
    Local cId     := ''
    Local oRest
    Local aHeader := {}
    Local cBody
    Local lOk     := .F.
    Local aCtes

    If Empty(cToken)
        Return lOk
    EndIf

    Default lLancada := .T.
    Default cChave   := ''

    If nId > 0
        cId := cValToChar(nId)
    ElseIf !Empty(cChave)
        // Localiza o ID via listagem pela chave de acesso
        aCtes := U_MPListarCte(CtoD(''), CtoD(''), '', 1, .F., cChave, '', '', .F.)
        If aCtes == NIL .Or. Len(aCtes) == 0
            Conout('CT-e nao encontrado para a chave: ' + cChave, 'API CT-e')
            Return lOk
        EndIf
        cId := cValToChar(aCtes[1][1])
    Else
        Conout('Informe o ID ou a chave de acesso do CT-e.', 'API CT-e')
        Return lOk
    EndIf

    oRest := FWRest():New(MP_BASE)
    aAdd(aHeader, 'Content-Type: application/json')
    aAdd(aHeader, 'Authorization: Bearer ' + cToken)
    aAdd(aHeader, 'User-Agent: TotvsProtheus ' + GetBuild())

    cBody := '{"lancada":' + If(lLancada, 'true', 'false') + '}'

    oRest:SetPath('/cte/' + cId + '/lancada')
    oRest:SetPostParams(cBody)

    If oRest:POST(aHeader)
        lOk := .T.
    Else
        Conout('Erro ao atualizar CT-e: ' + oRest:cResult, 'API CT-e')
    EndIf

    FreeObj(oRest)
Return lOk

3. Exemplo de uso — importar CT-e não lançados:

/*
 * Busca todos os CT-e não lançados do mês corrente
 * e marca cada um após processar no Protheus.
 * lTodas=.T. percorre todas as páginas automaticamente.
 */
User Function ImportaCTe()
    Local dIni   := CtoD('01/' + SubStr(DToS(Date()),5,2) + '/' + SubStr(DToS(Date()),1,4))
    Local aCtes  := U_MPListarCte(dIni, Date(), 'normal', 1, .T., '', '', '', .T.)
    Local i, aItem

    If aCtes == NIL
        Conout('Falha ao obter CT-e.', 'API CT-e')
        Return
    EndIf

    For i := 1 To Len(aCtes)
        aItem := aCtes[i]

        // [19] lancada — pula CT-e já lançados (redundante pois filtramos lNaoLancados=.T.)
        If aItem[19]
            Loop
        EndIf

        // *** Insira aqui a lógica de lançamento no Protheus ***
        // Ex: GravarCTe(aItem)

        // Marca como lançado pelo ID [1]
        U_MPDemarcaCte(aItem[1], .T., '')

    Next i

    MsgInfo('Importacao concluida! ' + cValToChar(Len(aCtes)) + ' CT-e processado(s).', 'API CT-e')
Return
Dica: Passe lNaoLancados := .T. em U_MPListarCte para receber apenas os CT-e ainda não processados — ideal para rotinas de importação incremental. Combine com lTodas := .T. para percorrer todas as páginas automaticamente.
ADVPL — Protheus (NF-e)

Mesma estrutura do módulo CT-e — utilize FWRest e parâmetros MV para as credenciais.

1. Função auxiliar — listar NF-e:

/*
 * U_MPListarNfe — Lista NF-e via API MeusPortais
 * Parâmetros:
 *   dDe         — Data inicial (Date)
 *   dAte        — Data final   (Date)
 *   cSituacao   — "" | "autorizado" | "cancelado" | "denegado"
 *   nTipoNf     — -1=todos | 0=Entrada | 1=Saida
 *   lTodas      — .T. percorre todas as paginas
 *   cCnpjEmit   — CNPJ emitente (somente digitos, opcional)
 *   cCnpjFilial — CNPJ filial (somente digitos, opcional)
 *   lNaoLancadas — .T. retorna somente nao lancadas
 * Retorno: array de arrays ou NIL em caso de erro
 */
User Function MPListarNfe(dDe, dAte, cSituacao, nTipoNf, lTodas, cCnpjEmit, cCnpjFilial, lNaoLancadas)
    Local cBase    := SuperGetMV('MV_MPURL',   .F., 'https://app.meusportais.com.br')
    Local cToken   := SuperGetMV('MV_MPTOKEN', .F., '')
    Local oRest    := FWRest():New(cBase)
    Local aResult  := {}
    Local nPage    := 1
    Local lCont    := .T.

    Default cSituacao    := ''
    Default nTipoNf      := -1
    Default lTodas       := .F.
    Default cCnpjEmit    := ''
    Default cCnpjFilial  := ''
    Default lNaoLancadas := .F.

    oRest:setHead('Authorization', 'Bearer ' + cToken)
    oRest:setHead('Accept',        'application/json')

    Do While lCont
        Local cQuery := '/api/nfe?per_page=100&page=' + cValToChar(nPage)
        If !Empty(dDe)
            cQuery += '&emissao_de='  + SubStr(DToS(dDe), 1,4) + '-' + SubStr(DToS(dDe), 5,2) + '-' + SubStr(DToS(dDe), 7,2)
        EndIf
        If !Empty(dAte)
            cQuery += '&emissao_ate=' + SubStr(DToS(dAte),1,4) + '-' + SubStr(DToS(dAte),5,2) + '-' + SubStr(DToS(dAte),7,2)
        EndIf
        If !Empty(cSituacao)
            cQuery += '&situacao=' + cSituacao
        EndIf
        If nTipoNf >= 0
            cQuery += '&tipo_nf=' + cValToChar(nTipoNf)
        EndIf
        If !Empty(cCnpjEmit)
            cQuery += '&cnpj_emitente=' + cCnpjEmit
        EndIf
        If !Empty(cCnpjFilial)
            cQuery += '&cnpj_filial=' + cCnpjFilial
        EndIf
        If lNaoLancadas
            cQuery += '&lancada=false'
        EndIf

        If !oRest:Get(cQuery)
            FreeObj(oRest)
            Return NIL
        EndIf

        Local jResp := JsonObject():New()
        jResp:fromJson(oRest:getResult())
        Local aData := jResp:GetJsonArray('data')
        Local jMeta := jResp:GetJsonObject('meta')
        Local nLast  := jMeta:GetJsonNumber('last_page')

        Local i
        For i := 1 To Len(aData)
            Local jItem := aData[i]
            AAdd(aResult, {;
                jItem:GetJsonNumber('id'),           ;  // [1]  ID interno
                jItem:GetJsonText('nsu'),            ;  // [2]  NSU
                jItem:GetJsonText('chave_acesso'),   ;  // [3]  Chave 44 digitos
                jItem:GetJsonText('data_emissao'),   ;  // [4]  Data emissao
                jItem:GetJsonText('numero_nfe'),     ;  // [5]  Numero NF-e
                jItem:GetJsonText('serie'),          ;  // [6]  Serie
                jItem:GetJsonNumber('tipo_nf'),      ;  // [7]  0=Entrada 1=Saida
                jItem:GetJsonText('tipo_nf_descricao'), ; // [8] "Entrada" | "Saida"
                jItem:GetJsonText('cnpj_filial'),    ;  // [9]  CNPJ filial
                jItem:GetJsonText('nome_filial'),    ;  // [10] Descricao filial
                jItem:GetJsonText('cnpj_emitente'),  ;  // [11] CNPJ emitente
                jItem:GetJsonText('razao_emitente'), ;  // [12] Razao social emitente
                jItem:GetJsonText('ie_emitente'),    ;  // [13] IE emitente
                jItem:GetJsonText('cnpj_destinatario'), ; // [14] CNPJ destinatario
                jItem:GetJsonText('razao_destinatario'), ; // [15] Razao social destinatario
                jItem:GetJsonNumber('valor_nf'),     ;  // [16] Valor total NF-e
                jItem:GetJsonText('situacao'),       ;  // [17] "autorizado" | "cancelado" | "denegado"
                jItem:GetJsonText('numero_protocolo'), ; // [18] Numero protocolo
                jItem:GetJsonLogical('lancada')      ;  // [19] .T./.F.
            })
        Next i

        If !lTodas .Or. nPage >= nLast
            lCont := .F.
        Else
            nPage++
        EndIf
    EndDo

    FreeObj(oRest)
Return aResult

2. Função auxiliar — marcar NF-e como lançada:

User Function MPMarcarNfeLancada(nId, lLancada)
    Local cBase  := SuperGetMV('MV_MPURL',   .F., 'https://app.meusportais.com.br')
    Local cToken := SuperGetMV('MV_MPTOKEN', .F., '')
    Local oRest  := FWRest():New(cBase)
    Local lOk    := .F.

    Default lLancada := .T.

    oRest:setHead('Authorization',  'Bearer ' + cToken)
    oRest:setHead('Accept',         'application/json')
    oRest:setHead('Content-Type',   'application/json')

    Local jBody := JsonObject():New()
    jBody['lancada'] := lLancada
    oRest:setBody(jBody:toJson())

    If oRest:Post('/api/nfe/' + cValToChar(nId) + '/lancada')
        Local jResp := JsonObject():New()
        jResp:fromJson(oRest:getResult())
        lOk := jResp:GetJsonLogical('lancada') == lLancada
    EndIf

    FreeObj(oRest)
Return lOk

3. Exemplo de uso — importar NF-e de entrada não lançadas:

/*
 * Busca todas as NF-e de entrada nao lancadas do mes corrente
 * e marca cada uma apos processar no Protheus.
 */
User Function ImportaNFe()
    Local dIni  := CtoD('01/' + SubStr(DToS(Date()),5,2) + '/' + SubStr(DToS(Date()),1,4))
    Local aNfes := U_MPListarNfe(dIni, Date(), 'autorizado', 0, .T., '', '', .T.)
    Local i, aItem

    If aNfes == NIL
        Conout('Falha ao obter NF-e.')
        Return
    EndIf

    For i := 1 To Len(aNfes)
        aItem := aNfes[i]

        // *** Insira aqui a logica de lancamento no Protheus ***
        // aItem[3]  = Chave de acesso (44 digitos)
        // aItem[5]  = Numero NF-e
        // aItem[11] = CNPJ emitente
        // aItem[16] = Valor NF-e

        // Marca como lancada apos processar
        U_MPMarcarNfeLancada(aItem[1], .T.)

        Conout('NF-e ' + aItem[5] + ' processada — Emitente: ' + aItem[12])
    Next i

    MsgInfo('Importacao concluida: ' + cValToChar(Len(aNfes)) + ' NF-e(s).', 'NF-e')
Return
Dica: Use nTipoNf=0 para filtrar apenas entradas (NF-e recebidas), nTipoNf=1 para saídas. Combine com lNaoLancadas=.T. para importação incremental.