Exemplos em PHP
Setup
composer require guzzlehttp/guzzle vlucas/phpdotenvMYSE_API_BASE=https://api.mysebr.com.br/nfemyse-v3/restMYSE_API_TOKEN=seu_token_aquiCliente HTTP centralizado
<?phpnamespace App;
use GuzzleHttp\Client;use GuzzleHttp\Exception\RequestException;
class ApiError extends \Exception{ public function __construct( public int $httpStatus, string $message, public mixed $payload = null, public ?string $requestId = null ) { parent::__construct($message); }}
class MyseApi{ private Client $client;
public function __construct() { $this->client = new Client([ 'base_uri' => $_ENV['MYSE_API_BASE'], 'timeout' => 30, 'headers' => [ 'Authorization' => 'Token ' . $_ENV['MYSE_API_TOKEN'], 'Content-Type' => 'application/json', ], 'http_errors' => false, ]); }
public function call(string $method, string $path, ?array $body = null): array { $options = $body ? ['json' => $body] : []; $res = $this->client->request($method, ltrim($path, '/'), $options);
$requestId = $res->getHeaderLine('X-Request-Id') ?: null; $bodyStr = (string) $res->getBody(); $json = json_decode($bodyStr, true) ?? [];
// Erro HTTP duro if ($res->getStatusCode() >= 400) { throw new ApiError( $res->getStatusCode(), $json['error']['message'] ?? "HTTP {$res->getStatusCode()}", $json, $requestId ); }
// Erro de domínio if (($json['status'] ?? null) === '999') { throw new ApiError( 200, $json['data']['erro'] ?? $json['descricao'] ?? 'erro', $json, $json['meta']['request_id'] ?? $requestId ); }
return $json; }}Cenário: emitir NFCe com polling
<?phpfunction emitirNFCe(MyseApi $api, array $pedido): array{ $body = [ 'serie' => '65', 'cfop' => '5102', 'numero-origem' => 'PED-' . $pedido['id'], 'tp_pagamento' => $pedido['forma_pagamento'], 'cliente' => $pedido['cpf_cnpj_cliente'], 'itens' => array_map(fn($i) => [ 'produto' => $i['sku'], 'quantidade' => (string) $i['qtd'], 'valor-unitario' => (string) $i['preco'], ], $pedido['itens']), ];
$emissao = $api->call('POST', '/nfce/emissao', $body);
if (!in_array($emissao['status'], ['001', '050'])) { throw new \RuntimeException("Emissão falhou: {$emissao['descricao']}"); }
$recibo = $emissao['data']['recibo']; error_log("[emissao] recibo=$recibo request_id={$emissao['meta']['request_id']}");
// Polling $terminais = ['004', '010', '900', '999']; $wait = 5.0; $inicio = microtime(true);
while (microtime(true) - $inicio < 300) { usleep((int) ($wait * 1_000_000)); $consulta = $api->call('GET', "/nfce/cupom/$recibo"); error_log("[polling] status={$consulta['status']}");
if (in_array($consulta['status'], $terminais)) { if ($consulta['status'] === '004') { return $consulta['data']; } throw new \RuntimeException("Status terminal não-sucesso: {$consulta['status']}"); }
$wait = min($wait * 1.5, 30); }
throw new \RuntimeException("Timeout aguardando recibo $recibo");}Retry com backoff
function comRetry(callable $fn, int $max = 3): mixed{ for ($i = 1; $i <= $max; $i++) { try { return $fn(); } catch (ApiError $e) { if (($e->payload['status'] ?? null) === '999') throw $e; if ($i === $max) throw $e; sleep((int) pow(2, $i - 1)); } }}
// Uso$nfce = comRetry(fn() => emitirNFCe($api, $pedido));Helper de polling reutilizável
<?phpconst TERMINAIS = ['004', '010', '900', '999'];
function aguardarRecibo(MyseApi $api, string $pathBase, string $recibo, int $timeoutSec = 300): array { $wait = 5.0; $inicio = microtime(true);
while (microtime(true) - $inicio < $timeoutSec) { usleep((int) ($wait * 1_000_000)); $resp = $api->call('GET', "$pathBase/$recibo"); if (in_array($resp['status'], TERMINAIS)) return $resp; $wait = min($wait * 1.5, 30); } throw new \RuntimeException("Timeout aguardando recibo $recibo");}Emitir NF-e (com transporte completo)
<?phpfunction emitirNFe(MyseApi $api, array $pedido): array { $body = [ 'serie' => '1', 'cfop' => '5102', 'numero-origem' => 'PED-' . $pedido['id'], 'tipo' => 'S', 'finalidade' => 'N', 'valor-despesas' => '0.00', 'cliente' => $pedido['cpf_cnpj_cliente'], 'transporte' => [ 'modalidade' => '0', 'transportadora' => $pedido['transportadora'], 'placa-veiculo' => $pedido['placa'], 'valor-frete' => $pedido['frete'] ?? '0.00', 'valor-seguro' => '0.00', 'peso-bruto' => $pedido['peso_bruto'], 'peso-liquido' => $pedido['peso_liquido'], 'quantidade-volume' => '1', 'especie-volume' => 'Caixa', 'marca-volume' => 'Embalagem', ], 'itens' => array_map(fn($i) => [ 'produto' => $i['sku'], 'quantidade' => (string) $i['qtd'], 'valor-unitario' => (string) $i['preco'], ], $pedido['itens']), 'faturas' => array_map(fn($f) => [ 'valor' => (string) $f['valor'], 'data' => $f['data'], ], $pedido['faturas'] ?? []), ];
$emissao = $api->call('POST', '/nfe/emissao', $body); if (!in_array($emissao['status'], ['001', '050'])) { throw new \RuntimeException("Emissão falhou: {$emissao['descricao']}"); }
$resultado = aguardarRecibo($api, '/nfe/nota', $emissao['data']['recibo']); if ($resultado['status'] !== '004') { throw new \RuntimeException("Status terminal não-sucesso: {$resultado['status']}"); } return $resultado['data']; // inclui sefaz.chave, url-danfe, url-xml}Cancelar NF-e
<?phpfunction cancelarNFe(MyseApi $api, string $chave, string $motivo): array { if (strlen($motivo) < 15 || strlen($motivo) > 255) { throw new \InvalidArgumentException('motivo deve ter entre 15 e 255 caracteres'); } $cancel = $api->call('POST', '/nfe/cancelamento', compact('chave', 'motivo')); if ($cancel['status'] !== '001') throw new \RuntimeException($cancel['descricao']); return aguardarRecibo($api, '/nfe/cancelamento', $cancel['data']['recibo']);}Lançar carta de correção (CC-e)
<?phpfunction cartaCorrecaoNFe(MyseApi $api, string $chave, string $textoCorrecao): array { if (strlen($textoCorrecao) < 15 || strlen($textoCorrecao) > 255) { throw new \InvalidArgumentException('texto deve ter entre 15 e 255 caracteres'); } // O campo "motivo" na CC-e é o TEXTO da correção (xCorrecao). $cce = $api->call('POST', '/nfe/correcao', ['chave' => $chave, 'motivo' => $textoCorrecao]); if ($cce['status'] !== '001') throw new \RuntimeException($cce['descricao']); return aguardarRecibo($api, '/nfe/correcao', $cce['data']['recibo']);}Cancelar NFC-e
<?phpfunction cancelarNFCe(MyseApi $api, string $chave, string $motivo): array { if (strlen($motivo) < 15 || strlen($motivo) > 255) { throw new \InvalidArgumentException('motivo deve ter entre 15 e 255 caracteres'); } $cancel = $api->call('POST', '/nfce/cancelamento', compact('chave', 'motivo')); if ($cancel['status'] !== '001') throw new \RuntimeException($cancel['descricao']); return aguardarRecibo($api, '/nfce/cancelamento', $cancel['data']['recibo']);}Emitir NFS-e (Nota Fiscal de Serviço)
<?phpfunction emitirNFSe(MyseApi $api, array $servico): array { $body = [ 'numero-origem' => 'OS-' . $servico['id'], 'observacao' => $servico['observacao'], 'nome-contato' => $servico['nome_contato'] ?? null, 'telefone-contato' => $servico['telefone_contato'] ?? null, 'data-fim' => $servico['data_fim'], 'cliente' => $servico['cpf_cnpj_cliente'], 'itens' => array_map(fn($i) => [ 'produto' => $i['codigo_servico'], 'quantidade' => (string) $i['qtd'], 'valor-unitario' => (string) $i['preco'], ], $servico['itens']), ];
$emissao = $api->call('POST', '/nfse/emissao', $body); if (!in_array($emissao['status'], ['001', '050'])) { throw new \RuntimeException("Emissão NFSe falhou: {$emissao['descricao']}"); }
$resultado = aguardarRecibo($api, '/nfse/nota', $emissao['data']['recibo']); if ($resultado['status'] !== '004') { throw new \RuntimeException("Status terminal não-sucesso: {$resultado['status']}"); } return $resultado['data'];}Cancelar NFS-e
<?phpfunction cancelarNFSe(MyseApi $api, string $chave, string $motivo): array { if (strlen($motivo) < 15 || strlen($motivo) > 255) { throw new \InvalidArgumentException('motivo deve ter entre 15 e 255 caracteres'); } return $api->call('POST', '/nfse/cancelamento', compact('chave', 'motivo'));}Reconhecer nota de fornecedor (MD-e)
<?php/** * 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 */function reconhecerNotaFornecedor(MyseApi $api, string $chave, string $codigo): array { $validos = ['210200', '210210', '210220', '210240']; if (!in_array($codigo, $validos, true)) { throw new \InvalidArgumentException("Código inválido: $codigo"); } $resp = $api->call('POST', '/nffornecedor/reconhecimento', [ 'chave' => $chave, 'codigo-reconhecimento' => $codigo, ]); if ($resp['status'] !== '001') throw new \RuntimeException($resp['descricao']); return aguardarRecibo($api, '/nffornecedor', $resp['data']['recibo']);}Listar com paginação
function listarTodosClientes(MyseApi $api): array{ $todos = []; $page = 1; $pageSize = 100;
while (true) { $resp = $api->call('GET', "/clientes?page=$page&page_size=$pageSize"); if ($resp['status'] !== '005' || !is_array($resp['data'] ?? null)) break; $todos = array_merge($todos, $resp['data']); if (count($resp['data']) < $pageSize) break; $page++; usleep(200_000); }
return $todos;}Tratamento de erros
try { $nfce = emitirNFCe($api, $pedido); echo "NFCe emitida: " . ($nfce['sefaz']['chave'] ?? '???') . "\n";} catch (ApiError $e) { error_log(json_encode([ 'event' => 'api_error', 'http_status' => $e->httpStatus, 'request_id' => $e->requestId, 'message' => $e->getMessage(), ])); throw $e;}Variação: cURL puro (sem Guzzle)
function curlCall(string $method, string $path, ?array $body = null): array { $ch = curl_init($_ENV['MYSE_API_BASE'] . $path); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => $method, CURLOPT_HTTPHEADER => [ 'Authorization: Token ' . $_ENV['MYSE_API_TOKEN'], 'Content-Type: application/json', ], CURLOPT_TIMEOUT => 30, CURLOPT_POSTFIELDS => $body ? json_encode($body) : null, CURLOPT_HEADER => true, ]); $resp = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); curl_close($ch);
$headers = substr($resp, 0, $headerSize); $body = substr($resp, $headerSize); return ['status' => $code, 'headers' => $headers, 'body' => json_decode($body, true)];}Health check (sem autenticação)
<?php$res = file_get_contents($_ENV['MYSE_API_BASE'] . '/health');$health = json_decode($res, true);// ["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.
<?phpfunction alterarNota(MyseApi $api, string $tipo, string $id, array $dados): array { // $tipo: 'nfe' | 'nfce' | 'nfse' return $api->call('PUT', "/$tipo/$id", $dados);}
// Uso:alterarNota($api, 'nfe', '12345', [ 'serie' => '1', 'cfop' => '5102', 'cliente' => '12345678000199', 'itens' => [ ['produto' => 'SKU-001', 'quantidade' => '3', 'valor-unitario' => '89.90'], ],]);Consulta detalhada por recibo
<?php$nfeCompleta = $api->call('GET', "/nfe/nota/$recibo/completa");$nfceCompleta = $api->call('GET', "/nfce/cupom/$recibo/completa");Listagens
<?php$nfes = $api->call('GET', '/nfe?page=1&page_size=20');$nfces = $api->call('GET', '/nfce?page=1&page_size=50');$nfses = $api->call('GET', '/nfse?dataInicial=2026-05-01&page=1&page_size=20');$fornecedor = $api->call('GET', '/nffornecedor?page=1&page_size=20');
// Forma legada (path-based)$nfesLegado = $api->call('GET', '/nfe/paginacao/1/20');Clientes (CRUD completo)
<?phpfunction cadastrarPF(MyseApi $api, array $dados): array { return $api->call('POST', '/clientes', [ 'tipo' => 'F', 'nome' => $dados['nome'], 'cpf' => $dados['cpf'], 'rg' => $dados['rg'] ?? null, 'consumidor-final' => '1', 'contato' => [ 'email' => $dados['email'] ?? null, 'telefone' => $dados['telefone'] ?? null, ], 'endereco' => $dados['endereco'], ]);}
function cadastrarPJ(MyseApi $api, array $dados): array { return $api->call('POST', '/clientes', [ 'tipo' => 'J', 'razao-social' => $dados['razao_social'], 'nome-fantasia' => $dados['nome_fantasia'] ?? null, 'cnpj' => $dados['cnpj'], 'inscricao-municipal' => $dados['inscricao_municipal'] ?? null, 'tipo-inscricao-estadual' => $dados['contribuinte'] ?? '9', 'inscricao-estadual' => $dados['inscricao_estadual'] ?? 'ISENTO', 'consumidor-final' => $dados['consumidor_final'] ?? '0', 'contato' => [ 'email' => $dados['email'] ?? null, 'telefone' => $dados['telefone'] ?? null, ], 'endereco' => $dados['endereco'], ]);}
// Consultar por CPF/CNPJ$cliente = $api->call('GET', '/clientes/12345678000199');
// Buscar por nome$encontrados = $api->call('GET', '/clientes/busca/exemplo');$top = $api->call('GET', '/clientes/busca/top_clientes');
// Atualizar$api->call('PUT', '/clientes/12345678000199', [ 'tipo' => 'J', 'razao-social' => 'Empresa Exemplo (Novo Nome) Ltda',]);
// Excluir$api->call('DELETE', '/clientes/12345678000199');Produtos (CRUD completo)
<?phpfunction cadastrarProduto(MyseApi $api, array $produto): array { return $api->call('POST', '/produtos', [ 'referencia' => $produto['sku'], 'nome' => $produto['nome'], 'valor' => (string) $produto['valor'], 'medida' => $produto['medida'] ?? 'UN', 'categoria' => $produto['categoria'] ?? null, 'ncm' => $produto['ncm'], 'origem' => $produto['origem'] ?? '0', 'cfop-preferencial' => $produto['cfop'] ?? '5102', 'tipo-produto' => 'P', 'configuracoes-fiscais' => $produto['config_fiscal'] ?? [], ]);}
function cadastrarServico(MyseApi $api, array $servico): array { return $api->call('POST', '/produtos', [ 'referencia' => $servico['sku'], 'nome' => $servico['nome'], 'valor' => (string) $servico['valor'], 'medida' => 'H', 'tipo-produto' => 'S', 'codigo-servico' => $servico['codigo_servico'], ]);}
// Consultar por referência$produto = $api->call('GET', '/produtos/SKU-001');
// Buscar por nome (1º resultado)$porNome = $api->call('GET', '/produtos/nome/Camiseta');
// Listar paginado com busca (use _todos para não filtrar)$todos = $api->call('GET', '/produtos/paginacao/1/20/_todos');$filtrados = $api->call('GET', '/produtos/paginacao/1/20/Camiseta');
// Atualizar$api->call('PUT', '/produtos/SKU-001', [ 'referencia' => 'SKU-001', 'nome' => 'Camiseta Polo M (Novo)', 'valor' => '99.90',]);
// Excluir$api->call('DELETE', '/produtos/SKU-001');