Pular para o conteúdo

Exemplos em JavaScript / TypeScript

Setup

Requer Node.js 18+ (que tem fetch nativo).

Terminal window
# .env (use dotenv ou similar)
MYSE_API_BASE=https://api.mysebr.com.br/nfemyse-v3/rest
MYSE_API_TOKEN=seu_token_aqui

Cliente HTTP centralizado

myse-api.js
const BASE = process.env.MYSE_API_BASE;
const TOKEN = process.env.MYSE_API_TOKEN;
export class ApiError extends Error {
constructor(httpStatus, message, payload, requestId) {
super(message);
this.httpStatus = httpStatus;
this.payload = payload;
this.requestId = requestId;
}
}
export async function mApi(method, path, body, options = {}) {
const url = `${BASE}${path}`;
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? 30_000);
try {
const res = await fetch(url, {
method,
headers: {
Authorization: `Token ${TOKEN}`,
'Content-Type': 'application/json',
},
body: body ? JSON.stringify(body) : undefined,
signal: controller.signal,
});
const requestId =
res.headers.get('x-request-id') ?? undefined;
if (!res.ok) {
const errBody = await res.json().catch(() => ({}));
throw new ApiError(
res.status,
errBody?.error?.message ?? `HTTP ${res.status}`,
errBody,
requestId
);
}
const json = await res.json();
if (json.status === '999') {
throw new ApiError(
200,
json.data?.erro ?? json.descricao,
json,
json.meta?.request_id ?? requestId
);
}
return json;
} finally {
clearTimeout(timeout);
}
}

Cenário: emitir NFCe completa

import { mApi, ApiError } from './myse-api.js';
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function emitirNFCe(pedido) {
// 1. Emitir
const emissao = await mApi('POST', '/nfce/emissao', {
serie: '65',
cfop: '5102',
'numero-origem': `PED-${pedido.id}`,
tp_pagamento: pedido.formaPagamento,
cliente: pedido.cpfCnpjCliente,
itens: pedido.itens.map((i) => ({
produto: i.sku,
quantidade: String(i.qtd),
'valor-unitario': String(i.preco),
})),
});
if (emissao.status !== '001' && emissao.status !== '050') {
throw new Error(`Emissão falhou: ${emissao.descricao}`);
}
const recibo = emissao.data.recibo;
console.log(`[emissao] recibo=${recibo} request_id=${emissao.meta.request_id}`);
// 2. Polling com backoff
const terminais = new Set(['004', '010', '900', '999']);
let wait = 2000;
const inicio = Date.now();
while (Date.now() - inicio < 5 * 60_000) {
await sleep(wait);
const consulta = await mApi('GET', `/nfce/cupom/${recibo}`);
console.log(`[polling] status=${consulta.status}`);
if (terminais.has(consulta.status)) {
if (consulta.status === '004') {
return consulta.data; // Inclui sefaz.chave, url-danfe, url-xml
}
throw new Error(`Status terminal não-sucesso: ${consulta.status}`);
}
wait = Math.min(wait * 1.5, 30_000);
}
throw new Error(`Timeout aguardando recibo ${recibo}`);
}

Retry com backoff em erros transitórios

async function comRetry(fn, max = 3) {
for (let i = 1; i <= max; i++) {
try {
return await fn();
} catch (err) {
// Não retentar erros de validação
if (err instanceof ApiError && err.payload?.status === '999') throw err;
if (i === max) throw err;
await sleep(1000 * Math.pow(2, i - 1)); // 1s, 2s, 4s
}
}
}
// Uso
const nfe = await comRetry(() => emitirNFCe(pedido));

Helper de polling reutilizável

const TERMINAIS = new Set(['004', '010', '900', '999']);
async function aguardarRecibo(pathBase, recibo, timeoutMs = 5 * 60_000) {
let wait = 2000;
const inicio = Date.now();
while (Date.now() - inicio < timeoutMs) {
await sleep(wait);
const resp = await mApi('GET', `${pathBase}/${recibo}`);
if (TERMINAIS.has(resp.status)) return resp;
wait = Math.min(wait * 1.5, 30_000);
}
throw new Error(`Timeout aguardando recibo ${recibo}`);
}

Emitir NF-e (com transporte completo)

async function emitirNFe(pedido) {
const emissao = await mApi('POST', '/nfe/emissao', {
serie: '1',
cfop: '5102',
'numero-origem': `PED-${pedido.id}`,
tipo: 'S',
finalidade: 'N',
'valor-despesas': '0.00',
cliente: pedido.cpfCnpjCliente,
transporte: {
modalidade: '0',
transportadora: pedido.transportadora,
'placa-veiculo': pedido.placa,
'valor-frete': pedido.frete ?? '0.00',
'valor-seguro': '0.00',
'peso-bruto': pedido.pesoBruto,
'peso-liquido': pedido.pesoLiquido,
'quantidade-volume': '1',
'especie-volume': 'Caixa',
'marca-volume': 'Embalagem',
},
itens: pedido.itens.map((i) => ({
produto: i.sku,
quantidade: String(i.qtd),
'valor-unitario': String(i.preco),
})),
faturas: pedido.faturas?.map((f) => ({ valor: String(f.valor), data: f.data })) ?? [],
});
if (!['001', '050'].includes(emissao.status)) {
throw new Error(`Emissão falhou: ${emissao.descricao}`);
}
const resultado = await aguardarRecibo('/nfe/nota', emissao.data.recibo);
if (resultado.status !== '004') {
throw new Error(`Status terminal não-sucesso: ${resultado.status}`);
}
return resultado.data; // inclui sefaz.chave, url-danfe, url-xml
}

Cancelar NF-e

async function cancelarNFe(chave, motivo) {
if (motivo.length < 15 || motivo.length > 255) {
throw new Error('Motivo deve ter entre 15 e 255 caracteres');
}
const cancel = await mApi('POST', '/nfe/cancelamento', { chave, motivo });
if (cancel.status !== '001') throw new Error(cancel.descricao);
return aguardarRecibo('/nfe/cancelamento', cancel.data.recibo);
}

Lançar carta de correção (CC-e)

async function cartaCorrecaoNFe(chave, textoCorrecao) {
if (textoCorrecao.length < 15 || textoCorrecao.length > 255) {
throw new Error('Texto da correção deve ter entre 15 e 255 caracteres');
}
// Nota: o campo "motivo" na CC-e é o TEXTO da correção (xCorrecao).
const cce = await mApi('POST', '/nfe/correcao', { chave, motivo: textoCorrecao });
if (cce.status !== '001') throw new Error(cce.descricao);
return aguardarRecibo('/nfe/correcao', cce.data.recibo);
}

Cancelar NFC-e

async function cancelarNFCe(chave, motivo) {
if (motivo.length < 15 || motivo.length > 255) {
throw new Error('Motivo deve ter entre 15 e 255 caracteres');
}
const cancel = await mApi('POST', '/nfce/cancelamento', { chave, motivo });
if (cancel.status !== '001') throw new Error(cancel.descricao);
return aguardarRecibo('/nfce/cancelamento', cancel.data.recibo);
}

Emitir NFS-e (Nota Fiscal de Serviço)

async function emitirNFSe(servico) {
const emissao = await mApi('POST', '/nfse/emissao', {
'numero-origem': `OS-${servico.id}`,
observacao: servico.observacao,
'nome-contato': servico.nomeContato,
'telefone-contato': servico.telefoneContato,
'data-fim': servico.dataFim,
cliente: servico.cpfCnpjCliente,
itens: servico.itens.map((i) => ({
produto: i.codigoServico,
quantidade: String(i.qtd),
'valor-unitario': String(i.preco),
})),
});
if (!['001', '050'].includes(emissao.status)) {
throw new Error(`Emissão NFSe falhou: ${emissao.descricao}`);
}
const resultado = await aguardarRecibo('/nfse/nota', emissao.data.recibo);
if (resultado.status !== '004') {
throw new Error(`Status terminal não-sucesso: ${resultado.status}`);
}
return resultado.data;
}

Cancelar NFS-e

async function cancelarNFSe(chave, motivo) {
if (motivo.length < 15 || motivo.length > 255) {
throw new Error('Motivo deve ter entre 15 e 255 caracteres');
}
return mApi('POST', '/nfse/cancelamento', { chave, motivo });
}

Reconhecer nota de fornecedor (MD-e)

/**
* Códigos de reconhecimento:
* '210200' — Confirmação da operação (terminal, irreversível)
* '210210' — Ciência da operação (provisório, 15 dias)
* '210220' — Desconhecimento da operação
* '210240' — Operação não realizada
*/
async function reconhecerNotaFornecedor(chave, codigoReconhecimento) {
const VALIDOS = new Set(['210200', '210210', '210220', '210240']);
if (!VALIDOS.has(codigoReconhecimento)) {
throw new Error(`Código inválido: ${codigoReconhecimento}`);
}
const resp = await mApi('POST', '/nffornecedor/reconhecimento', {
chave,
'codigo-reconhecimento': codigoReconhecimento,
});
if (resp.status !== '001') throw new Error(resp.descricao);
return aguardarRecibo('/nffornecedor', resp.data.recibo);
}

Sincronizar todos os clientes

async function listarTodosClientes() {
const todos = [];
let page = 1;
const pageSize = 100;
while (true) {
const resp = await mApi('GET', `/clientes?page=${page}&page_size=${pageSize}`);
if (resp.status !== '005' || !Array.isArray(resp.data)) break;
todos.push(...resp.data);
if (resp.data.length < pageSize) break;
page++;
await sleep(200);
}
return todos;
}

Tratamento de erros completo

try {
const nfe = await emitirNFCe(pedido);
console.log('NFCe emitida:', nfe.sefaz?.chave);
} catch (err) {
if (err instanceof ApiError) {
console.error(
`API Error HTTP=${err.httpStatus} requestId=${err.requestId}`,
err.message,
err.payload
);
// Logar para suporte: requestId é o que importa
} else {
console.error('Erro inesperado:', err);
}
}

Health check (sem autenticação)

async function health() {
const res = await fetch(`${BASE}/health`);
return res.json();
// { status: 'ok', database: 'ok', timestamp: '...' }
}

Alterar nota antes da emissão (PUT)

Disponível em NF-e (/nfe/{id}), NFC-e (/nfce/{id}) e NFS-e (/nfse/{id}). Só funciona enquanto a nota ainda não foi submetida para emissão.

async function alterarNota(tipo, id, dadosAtualizados) {
// tipo: 'nfe' | 'nfce' | 'nfse'
return mApi('PUT', `/${tipo}/${id}`, dadosAtualizados);
}
// Uso:
await alterarNota('nfe', '12345', {
serie: '1', cfop: '5102', cliente: '12345678000199',
itens: [{ produto: 'SKU-001', quantidade: '3', 'valor-unitario': '89.90' }],
});

Consulta detalhada por recibo

// NF-e completa (inclui itens, transporte, cliente, sefaz)
const nfeCompleta = await mApi('GET', `/nfe/nota/${recibo}/completa`);
// NFC-e completa
const nfceCompleta = await mApi('GET', `/nfce/cupom/${recibo}/completa`);

Listagens

// NF-es paginadas
const nfes = await mApi('GET', '/nfe?page=1&page_size=20');
// NFC-es
const nfces = await mApi('GET', '/nfce?page=1&page_size=50');
// NFS-es com filtro de data
const nfses = await mApi(
'GET',
'/nfse?dataInicial=2026-05-01&page=1&page_size=20'
);
// Notas de fornecedor
const fornecedor = await mApi('GET', '/nffornecedor?page=1&page_size=20');
// Forma legada (path-based)
const nfesLegado = await mApi('GET', '/nfe/paginacao/1/20');

Clientes (CRUD completo)

// Cadastrar pessoa física
async function cadastrarPF(dados) {
return mApi('POST', '/clientes', {
tipo: 'F',
nome: dados.nome,
cpf: dados.cpf,
rg: dados.rg,
'consumidor-final': '1',
contato: { email: dados.email, telefone: dados.telefone },
endereco: dados.endereco,
});
}
// Cadastrar pessoa jurídica
async function cadastrarPJ(dados) {
return mApi('POST', '/clientes', {
tipo: 'J',
'razao-social': dados.razaoSocial,
'nome-fantasia': dados.nomeFantasia,
cnpj: dados.cnpj,
'inscricao-municipal': dados.inscricaoMunicipal,
'tipo-inscricao-estadual': dados.contribuinte ?? '9',
'inscricao-estadual': dados.inscricaoEstadual ?? 'ISENTO',
'consumidor-final': dados.consumidorFinal ?? '0',
contato: { email: dados.email, telefone: dados.telefone },
endereco: dados.endereco,
});
}
// Consultar por CPF/CNPJ
const cliente = await mApi('GET', '/clientes/12345678000199');
// Buscar por nome (parcial)
const encontrados = await mApi('GET', '/clientes/busca/exemplo');
// Top 20 clientes mais relevantes
const top = await mApi('GET', '/clientes/busca/top_clientes');
// Atualizar
await mApi('PUT', '/clientes/12345678000199', {
tipo: 'J',
'razao-social': 'Empresa Exemplo (Novo Nome) Ltda',
});
// Excluir
await mApi('DELETE', '/clientes/12345678000199');

Produtos (CRUD completo)

// Cadastrar produto com configuração fiscal
async function cadastrarProduto(produto) {
return mApi('POST', '/produtos', {
referencia: produto.sku,
nome: produto.nome,
valor: String(produto.valor),
medida: produto.medida ?? 'UN',
categoria: produto.categoria,
ncm: produto.ncm,
origem: produto.origem ?? '0',
'cfop-preferencial': produto.cfop ?? '5102',
'tipo-produto': 'P',
'configuracoes-fiscais': produto.configFiscal ?? [],
});
}
// Cadastrar serviço
async function cadastrarServico(servico) {
return mApi('POST', '/produtos', {
referencia: servico.sku,
nome: servico.nome,
valor: String(servico.valor),
medida: 'H',
'tipo-produto': 'S',
'codigo-servico': servico.codigoServico,
});
}
// Consultar por referência
const produto = await mApi('GET', '/produtos/SKU-001');
// Buscar por nome (1º resultado)
const porNome = await mApi('GET', '/produtos/nome/Camiseta');
// Listar paginado com busca (use _todos para não filtrar)
const todos = await mApi('GET', '/produtos/paginacao/1/20/_todos');
const filtrados = await mApi('GET', '/produtos/paginacao/1/20/Camiseta');
// Atualizar
await mApi('PUT', '/produtos/SKU-001', {
referencia: 'SKU-001',
nome: 'Camiseta Polo M (Novo)',
valor: '99.90',
});
// Excluir
await mApi('DELETE', '/produtos/SKU-001');