Exemplos em Go
Setup
Requer Go 1.21+. Sem dependências externas (usa stdlib).
export MYSE_API_BASE="https://api.mysebr.com.br/nfemyse-v3/rest"export MYSE_API_TOKEN="seu_token_aqui"Cliente HTTP centralizado
package myse
import ( "bytes" "context" "encoding/json" "fmt" "io" "net/http" "os" "time")
type ApiResponse struct { Status string `json:"status"` Descricao string `json:"descricao"` Data json.RawMessage `json:"data,omitempty"` Meta *Meta `json:"meta,omitempty"`}
type Meta struct { RequestID string `json:"request_id"` Timestamp string `json:"timestamp"`}
type ApiError struct { HTTPStatus int Message string Payload json.RawMessage RequestID string}
func (e *ApiError) Error() string { return fmt.Sprintf("[%d] %s (request_id=%s)", e.HTTPStatus, e.Message, e.RequestID)}
type Client struct { Base string Token string HTTP *http.Client}
func New() *Client { return &Client{ Base: os.Getenv("MYSE_API_BASE"), Token: os.Getenv("MYSE_API_TOKEN"), HTTP: &http.Client{Timeout: 30 * time.Second}, }}
func (c *Client) Call(ctx context.Context, method, path string, body any) (*ApiResponse, error) { var reader io.Reader if body != nil { b, err := json.Marshal(body) if err != nil { return nil, err } reader = bytes.NewReader(b) }
req, err := http.NewRequestWithContext(ctx, method, c.Base+path, reader) if err != nil { return nil, err } req.Header.Set("Authorization", "Token "+c.Token) req.Header.Set("Content-Type", "application/json")
res, err := c.HTTP.Do(req) if err != nil { return nil, err } defer res.Body.Close()
bodyBytes, _ := io.ReadAll(res.Body) requestID := res.Header.Get("X-Request-Id")
if res.StatusCode >= 400 { return nil, &ApiError{ HTTPStatus: res.StatusCode, Message: fmt.Sprintf("HTTP %d", res.StatusCode), Payload: bodyBytes, RequestID: requestID, } }
var apiResp ApiResponse if err := json.Unmarshal(bodyBytes, &apiResp); err != nil { return nil, err }
if apiResp.Status == "999" { // Extrai erro do data var data map[string]any json.Unmarshal(apiResp.Data, &data) msg, _ := data["erro"].(string) if msg == "" { msg = apiResp.Descricao } rid := requestID if apiResp.Meta != nil && apiResp.Meta.RequestID != "" { rid = apiResp.Meta.RequestID } return nil, &ApiError{HTTPStatus: 200, Message: msg, Payload: bodyBytes, RequestID: rid} }
return &apiResp, nil}Cenário: emitir NFCe com polling
package main
import ( "context" "encoding/json" "fmt" "math" "time")
var terminais = map[string]bool{"004": true, "010": true, "900": true, "999": true}
func EmitirNFCe(ctx context.Context, c *myse.Client, pedido Pedido) (json.RawMessage, error) { body := map[string]any{ "serie": "65", "cfop": "5102", "numero-origem": fmt.Sprintf("PED-%d", pedido.ID), "tp_pagamento": pedido.FormaPagamento, "cliente": pedido.CpfCnpjCliente, "itens": buildItens(pedido.Itens), }
emissao, err := c.Call(ctx, "POST", "/nfce/emissao", body) if err != nil { return nil, err } if emissao.Status != "001" && emissao.Status != "050" { return nil, fmt.Errorf("emissão falhou: %s", emissao.Descricao) }
var emissaoData map[string]string json.Unmarshal(emissao.Data, &emissaoData) recibo := emissaoData["recibo"] fmt.Printf("[emissao] recibo=%s request_id=%s\n", recibo, emissao.Meta.RequestID)
wait := 5 * time.Second deadline := time.Now().Add(5 * time.Minute)
for time.Now().Before(deadline) { time.Sleep(wait) consulta, err := c.Call(ctx, "GET", "/nfce/cupom/"+recibo, nil) if err != nil { return nil, err } fmt.Printf("[polling] status=%s\n", consulta.Status)
if terminais[consulta.Status] { if consulta.Status == "004" { return consulta.Data, nil } return nil, fmt.Errorf("status terminal não-sucesso: %s", consulta.Status) }
wait = time.Duration(math.Min(float64(wait)*1.5, float64(30*time.Second))) }
return nil, fmt.Errorf("timeout aguardando recibo %s", recibo)}
func buildItens(itens []Item) []map[string]string { out := make([]map[string]string, len(itens)) for i, it := range itens { out[i] = map[string]string{ "produto": it.SKU, "quantidade": fmt.Sprintf("%d", it.Qtd), "valor-unitario": fmt.Sprintf("%.2f", it.Preco), } } return out}Retry com backoff
func ComRetry[T any](ctx context.Context, fn func() (T, error), max int) (T, error) { var zero T var lastErr error
for i := 1; i <= max; i++ { result, err := fn() if err == nil { return result, nil }
// Erros de validação: não retentar if apiErr, ok := err.(*myse.ApiError); ok { var p map[string]any json.Unmarshal(apiErr.Payload, &p) if p["status"] == "999" { return zero, err } }
lastErr = err if i < max { time.Sleep(time.Duration(math.Pow(2, float64(i-1))) * time.Second) } }
return zero, lastErr}Helper de polling reutilizável
var terminais = map[string]bool{"004": true, "010": true, "900": true, "999": true}
func AguardarRecibo(ctx context.Context, c *myse.Client, pathBase, recibo string, timeout time.Duration) (*myse.ApiResponse, error) { if timeout == 0 { timeout = 5 * time.Minute } wait := 5 * time.Second inicio := time.Now()
for time.Since(inicio) < timeout { time.Sleep(wait) resp, err := c.Call(ctx, "GET", pathBase+"/"+recibo, nil) if err != nil { return nil, err } if terminais[resp.Status] { return resp, nil } wait = time.Duration(math.Min(float64(wait)*1.5, float64(30*time.Second))) } return nil, fmt.Errorf("timeout aguardando recibo %s", recibo)}
func validarMotivo(motivo string) error { if len(motivo) < 15 || len(motivo) > 255 { return fmt.Errorf("motivo deve ter entre 15 e 255 caracteres") } return nil}Emitir NF-e (com transporte completo)
func EmitirNFe(ctx context.Context, c *myse.Client, pedido Pedido) (json.RawMessage, error) { faturas := make([]map[string]string, 0, len(pedido.Faturas)) for _, f := range pedido.Faturas { faturas = append(faturas, map[string]string{ "valor": fmt.Sprintf("%.2f", f.Valor), "data": f.Data, }) }
body := map[string]any{ "serie": "1", "cfop": "5102", "numero-origem": fmt.Sprintf("PED-%d", pedido.ID), "tipo": "S", "finalidade": "N", "valor-despesas": "0.00", "cliente": pedido.CpfCnpjCliente, "transporte": map[string]string{ "modalidade": "0", "transportadora": pedido.Transportadora, "placa-veiculo": pedido.Placa, "valor-frete": pedido.Frete, "valor-seguro": "0.00", "peso-bruto": pedido.PesoBruto, "peso-liquido": pedido.PesoLiquido, "quantidade-volume": "1", "especie-volume": "Caixa", "marca-volume": "Embalagem", }, "itens": buildItens(pedido.Itens), "faturas": faturas, }
emissao, err := c.Call(ctx, "POST", "/nfe/emissao", body) if err != nil { return nil, err } if emissao.Status != "001" && emissao.Status != "050" { return nil, fmt.Errorf("emissão falhou: %s", emissao.Descricao) }
var d map[string]string json.Unmarshal(emissao.Data, &d) resultado, err := AguardarRecibo(ctx, c, "/nfe/nota", d["recibo"], 0) if err != nil { return nil, err } if resultado.Status != "004" { return nil, fmt.Errorf("status terminal não-sucesso: %s", resultado.Status) } return resultado.Data, nil // inclui sefaz.chave, url-danfe, url-xml}Cancelar NF-e
func CancelarNFe(ctx context.Context, c *myse.Client, chave, motivo string) (*myse.ApiResponse, error) { if err := validarMotivo(motivo); err != nil { return nil, err } cancel, err := c.Call(ctx, "POST", "/nfe/cancelamento", map[string]string{ "chave": chave, "motivo": motivo, }) if err != nil { return nil, err } if cancel.Status != "001" { return nil, fmt.Errorf(cancel.Descricao) } var d map[string]string json.Unmarshal(cancel.Data, &d) return AguardarRecibo(ctx, c, "/nfe/cancelamento", d["recibo"], 0)}Lançar carta de correção (CC-e)
// O campo "motivo" na CC-e é o TEXTO da correção (xCorrecao).func CartaCorrecaoNFe(ctx context.Context, c *myse.Client, chave, textoCorrecao string) (*myse.ApiResponse, error) { if err := validarMotivo(textoCorrecao); err != nil { return nil, err } cce, err := c.Call(ctx, "POST", "/nfe/correcao", map[string]string{ "chave": chave, "motivo": textoCorrecao, }) if err != nil { return nil, err } if cce.Status != "001" { return nil, fmt.Errorf(cce.Descricao) } var d map[string]string json.Unmarshal(cce.Data, &d) return AguardarRecibo(ctx, c, "/nfe/correcao", d["recibo"], 0)}Cancelar NFC-e
func CancelarNFCe(ctx context.Context, c *myse.Client, chave, motivo string) (*myse.ApiResponse, error) { if err := validarMotivo(motivo); err != nil { return nil, err } cancel, err := c.Call(ctx, "POST", "/nfce/cancelamento", map[string]string{ "chave": chave, "motivo": motivo, }) if err != nil { return nil, err } if cancel.Status != "001" { return nil, fmt.Errorf(cancel.Descricao) } var d map[string]string json.Unmarshal(cancel.Data, &d) return AguardarRecibo(ctx, c, "/nfce/cancelamento", d["recibo"], 0)}Emitir NFS-e (Nota Fiscal de Serviço)
func EmitirNFSe(ctx context.Context, c *myse.Client, servico Servico) (json.RawMessage, error) { itens := make([]map[string]string, 0, len(servico.Itens)) for _, i := range servico.Itens { itens = append(itens, map[string]string{ "produto": i.CodigoServico, "quantidade": fmt.Sprintf("%d", i.Qtd), "valor-unitario": fmt.Sprintf("%.2f", i.Preco), }) }
body := map[string]any{ "numero-origem": fmt.Sprintf("OS-%d", servico.ID), "observacao": servico.Observacao, "nome-contato": servico.NomeContato, "telefone-contato": servico.TelefoneContato, "data-fim": servico.DataFim, "cliente": servico.CpfCnpjCliente, "itens": itens, }
emissao, err := c.Call(ctx, "POST", "/nfse/emissao", body) if err != nil { return nil, err } if emissao.Status != "001" && emissao.Status != "050" { return nil, fmt.Errorf("emissão NFSe falhou: %s", emissao.Descricao) }
var d map[string]string json.Unmarshal(emissao.Data, &d) resultado, err := AguardarRecibo(ctx, c, "/nfse/nota", d["recibo"], 0) if err != nil { return nil, err } if resultado.Status != "004" { return nil, fmt.Errorf("status terminal não-sucesso: %s", resultado.Status) } return resultado.Data, nil}Cancelar NFS-e
func CancelarNFSe(ctx context.Context, c *myse.Client, chave, motivo string) (*myse.ApiResponse, error) { if err := validarMotivo(motivo); err != nil { return nil, err } return c.Call(ctx, "POST", "/nfse/cancelamento", map[string]string{ "chave": chave, "motivo": 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 realizadafunc ReconhecerNotaFornecedor(ctx context.Context, c *myse.Client, chave, codigo string) (*myse.ApiResponse, error) { validos := map[string]bool{"210200": true, "210210": true, "210220": true, "210240": true} if !validos[codigo] { return nil, fmt.Errorf("código inválido: %s", codigo) } resp, err := c.Call(ctx, "POST", "/nffornecedor/reconhecimento", map[string]string{ "chave": chave, "codigo-reconhecimento": codigo, }) if err != nil { return nil, err } if resp.Status != "001" { return nil, fmt.Errorf(resp.Descricao) } var d map[string]string json.Unmarshal(resp.Data, &d) return AguardarRecibo(ctx, c, "/nffornecedor", d["recibo"], 0)}Listar com paginação
func ListarTodosClientes(ctx context.Context, c *myse.Client) ([]json.RawMessage, error) { var todos []json.RawMessage page := 1 pageSize := 100
for { path := fmt.Sprintf("/clientes?page=%d&page_size=%d", page, pageSize) resp, err := c.Call(ctx, "GET", path, nil) if err != nil { return nil, err } if resp.Status != "005" { break }
var batch []json.RawMessage json.Unmarshal(resp.Data, &batch) if len(batch) == 0 { break } todos = append(todos, batch...) if len(batch) < pageSize { break } page++ time.Sleep(200 * time.Millisecond) }
return todos, nil}Tratamento de erros
func main() { ctx := context.Background() c := myse.New()
data, err := EmitirNFCe(ctx, c, pedido) if err != nil { if apiErr, ok := err.(*myse.ApiError); ok { log.Printf("API error: status=%d request_id=%s msg=%s", apiErr.HTTPStatus, apiErr.RequestID, apiErr.Message) } os.Exit(1) } log.Printf("NFCe emitida: %s", string(data))}Health check (sem autenticação)
res, _ := http.Get(myse.Base + "/health")defer res.Body.Close()var health map[string]stringjson.NewDecoder(res.Body).Decode(&health)// map[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.
// tipo: "nfe" | "nfce" | "nfse"func AlterarNota(ctx context.Context, c *myse.Client, tipo, id string, dados any) (*myse.ApiResponse, error) { return c.Call(ctx, "PUT", fmt.Sprintf("/%s/%s", tipo, id), dados)}
// Uso:AlterarNota(ctx, c, "nfe", "12345", map[string]any{ "serie": "1", "cfop": "5102", "cliente": "12345678000199", "itens": []map[string]string{ {"produto": "SKU-001", "quantidade": "3", "valor-unitario": "89.90"}, },})Consulta detalhada por recibo
nfeCompleta, _ := c.Call(ctx, "GET", "/nfe/nota/"+recibo+"/completa", nil)nfceCompleta, _ := c.Call(ctx, "GET", "/nfce/cupom/"+recibo+"/completa", nil)Listagens
nfes, _ := c.Call(ctx, "GET", "/nfe?page=1&page_size=20", nil)nfces, _ := c.Call(ctx, "GET", "/nfce?page=1&page_size=50", nil)nfses, _ := c.Call(ctx, "GET", "/nfse?dataInicial=2026-05-01&page=1&page_size=20", nil)fornecedor, _ := c.Call(ctx, "GET", "/nffornecedor?page=1&page_size=20", nil)
// Forma legada (path-based)nfesLegado, _ := c.Call(ctx, "GET", "/nfe/paginacao/1/20", nil)Clientes (CRUD completo)
type PessoaFisica struct { Nome, Cpf, Rg, Email, Telefone string Endereco map[string]string}
func CadastrarPF(ctx context.Context, c *myse.Client, pf PessoaFisica) (*myse.ApiResponse, error) { return c.Call(ctx, "POST", "/clientes", map[string]any{ "tipo": "F", "nome": pf.Nome, "cpf": pf.Cpf, "rg": pf.Rg, "consumidor-final": "1", "contato": map[string]string{"email": pf.Email, "telefone": pf.Telefone}, "endereco": pf.Endereco, })}
type PessoaJuridica struct { RazaoSocial, NomeFantasia, Cnpj, InscricaoMunicipal string Contribuinte, InscricaoEstadual, Email, Telefone string Endereco map[string]string}
func CadastrarPJ(ctx context.Context, c *myse.Client, pj PessoaJuridica) (*myse.ApiResponse, error) { contribuinte := pj.Contribuinte if contribuinte == "" { contribuinte = "9" } ie := pj.InscricaoEstadual if ie == "" { ie = "ISENTO" } return c.Call(ctx, "POST", "/clientes", map[string]any{ "tipo": "J", "razao-social": pj.RazaoSocial, "nome-fantasia": pj.NomeFantasia, "cnpj": pj.Cnpj, "inscricao-municipal": pj.InscricaoMunicipal, "tipo-inscricao-estadual": contribuinte, "inscricao-estadual": ie, "consumidor-final": "0", "contato": map[string]string{"email": pj.Email, "telefone": pj.Telefone}, "endereco": pj.Endereco, })}
// Consultar por CPF/CNPJcliente, _ := c.Call(ctx, "GET", "/clientes/12345678000199", nil)
// Buscar por nomeencontrados, _ := c.Call(ctx, "GET", "/clientes/busca/exemplo", nil)top, _ := c.Call(ctx, "GET", "/clientes/busca/top_clientes", nil)
// Atualizarc.Call(ctx, "PUT", "/clientes/12345678000199", map[string]string{ "tipo": "J", "razao-social": "Empresa Exemplo (Novo Nome) Ltda",})
// Excluirc.Call(ctx, "DELETE", "/clientes/12345678000199", nil)Produtos (CRUD completo)
type Produto struct { Sku, Nome, Medida, Categoria, Ncm, Origem, Cfop string Valor float64 ConfiguracoesFiscais []any}
func CadastrarProduto(ctx context.Context, c *myse.Client, p Produto) (*myse.ApiResponse, error) { medida := p.Medida if medida == "" { medida = "UN" } origem := p.Origem if origem == "" { origem = "0" } cfop := p.Cfop if cfop == "" { cfop = "5102" } return c.Call(ctx, "POST", "/produtos", map[string]any{ "referencia": p.Sku, "nome": p.Nome, "valor": fmt.Sprintf("%.2f", p.Valor), "medida": medida, "categoria": p.Categoria, "ncm": p.Ncm, "origem": origem, "cfop-preferencial": cfop, "tipo-produto": "P", "configuracoes-fiscais": p.ConfiguracoesFiscais, })}
type Servico struct { Sku, Nome, CodigoServico string Valor float64}
func CadastrarServico(ctx context.Context, c *myse.Client, s Servico) (*myse.ApiResponse, error) { return c.Call(ctx, "POST", "/produtos", map[string]any{ "referencia": s.Sku, "nome": s.Nome, "valor": fmt.Sprintf("%.2f", s.Valor), "medida": "H", "tipo-produto": "S", "codigo-servico": s.CodigoServico, })}
// Consultarproduto, _ := c.Call(ctx, "GET", "/produtos/SKU-001", nil)porNome, _ := c.Call(ctx, "GET", "/produtos/nome/Camiseta", nil)
// Listar paginado com busca (use _todos para não filtrar)todos, _ := c.Call(ctx, "GET", "/produtos/paginacao/1/20/_todos", nil)filtrados, _ := c.Call(ctx, "GET", "/produtos/paginacao/1/20/Camiseta", nil)
// Atualizarc.Call(ctx, "PUT", "/produtos/SKU-001", map[string]string{ "referencia": "SKU-001", "nome": "Camiseta Polo M (Novo)", "valor": "99.90",})
// Excluirc.Call(ctx, "DELETE", "/produtos/SKU-001", nil)