Autenticação, erros e limites
Chave de API
Toda chamada (menos GET /openapi.json) leva a chave da conta em um destes formatos:
Authorization: Bearer nfe_SUA_CHAVE_AQUI
ou HTTP Basic, com a chave como usuário e a senha vazia (o mesmo formato do Focus NFe, para quem já tem o cliente HTTP configurado assim):
curl -u "nfe_SUA_CHAVE_AQUI:" https://srv1839254.hstgr.cloud/api/v2/empresas
Envie também Accept: application/json e, nos POST/PUT/PATCH/DELETE com corpo, Content-Type: application/json.
- A chave é entregue uma única vez, na criação. A plataforma guarda só um hash dela: se você perder, peça uma nova e revogue a antiga.
- Uma chave pode ter validade. Chave revogada, vencida ou inexistente responde sempre o mesmo
401, para não ensinar nada a quem está adivinhando. - Conta desativada responde
403 conta_inativa. - Rotação sem parada: peça uma chave nova, coloque-a no seu sistema e só então revogue a antiga. Várias chaves valem ao mesmo tempo.
- Trate a chave como senha: não a coloque em código-fonte, front-end ou repositório.
Formato dos erros
Qualquer erro tem o mesmo corpo:
{ "codigo": "requisicao_invalida", "mensagem": "O campo nome destinatario é obrigatório.", "erros": { "nome_destinatario": ["O campo nome destinatario é obrigatório."] } }
codigo: estável. Programe contra ele, não contra a mensagem.mensagem: para uma pessoa ler (em português; pode mudar de redação).erros(só na validação): todos os problemas de uma vez, por campo, com o caminho (items.0.codigo_ncm,formas_pagamento.1.valor_pagamento).
Veja todos os códigos e o que fazer em cada um em Erros.
| HTTP | Quando |
|---|---|
200 |
sucesso; ou reenvio de uma nota que já existe com o mesmo conteúdo, em estado final |
201 |
criado (empresa, webhook, produto novo) |
202 |
aceito; o resultado depende da SEFAZ e vem depois |
204 |
removido |
401 |
chave ausente, inválida, revogada ou vencida |
403 |
conta desativada |
404 |
não existe (ou não é da sua conta) |
409 |
conflito: a ref já pertence a uma nota com outro conteúdo |
422 |
a requisição é inválida ou o cálculo fiscal recusou |
429 |
limite de requisições por minuto estourado |
5xx |
falha da plataforma: tente de novo (com a mesma ref, é seguro) |
Limites por minuto
Cada chave tem o seu balde: uma chave que dispara chamadas demais não gasta a cota das outras.
| Balde | Padrão | O que conta |
|---|---|---|
| geral | 300 por minuto | toda chamada autenticada |
| emissão | 120 por minuto | POST /nfe |
| sensível | 10 por minuto | POST /empresas e PUT /empresas/{cnpj}/certificado |
Os padrões podem ser ajustados por conta. Além disso há um limite por IP, antes de a chave ser conferida (1200 por minuto), contra quem fica adivinhando chaves.
Toda resposta autenticada traz X-RateLimit-Limit e X-RateLimit-Remaining. Ao estourar:
HTTP/1.1 429 Too Many Requests
Retry-After: 51
X-RateLimit-Limit: 300
{ "codigo": "limite_de_requisicoes", "mensagem": "Muitas requisições. Tente de novo em 51 segundo(s)." }
Espere Retry-After segundos e repita. Não faça laço apertado de tentativas: veja o backoff recomendado.
X-Request-Id e o log de requisições
Toda resposta autenticada traz X-Request-Id. Guarde-o nos seus logs e cite-o ao pedir suporte: ele identifica a chamada exata do nosso lado.
GET /requisicoes mostra o log da sua conta (todas as chaves), das mais recentes para as mais antigas:
curl -s "https://srv1839254.hstgr.cloud/api/v2/requisicoes?status=4xx&metodo=POST&per_page=20" -H "Authorization: Bearer $CHAVE"
Filtros: status (código exato como 404, ou a classe 4xx/5xx), metodo, caminho (contém), desde (data/hora ISO 8601; codifique o + do fuso como %2B), per_page (até 100). Cada item tem id (o mesmo X-Request-Id), metodo, caminho, status, duracao_ms, chave (prefixo da chave usada), ip, user_agent e criada_em.
O log guarda só metadados: nunca o corpo, a query string nem os cabeçalhos (neles há certificado, senha e dados do destinatário). Fica por 30 dias.
Paginação
Listas grandes (/produtos, /webhooks/{id}/entregas, /requisicoes) são paginadas: ?per_page=25 (máximo 100) e ?page=2. A resposta traz:
{ "data": [ ... ], "links": { "first": "...?page=1", "last": "...?page=14", "prev": null, "next": "...?page=2" },
"meta": { "current_page": 1, "last_page": 14, "per_page": 2, "total": 27 } }
Siga links.next até ele ser null. As listas curtas (/empresas, /webhooks, /nfe/inutilizacoes) vêm inteiras em data, sem paginação.
Convenções de dados
- Valores monetários: reais, como número JSON com ponto decimal (
100.00,0.3333no preço unitário). Totais aceitam até 2 casas; preço unitário até 10; quantidade até 4. Nas respostas,valor_totalé um número em reais. - Datas e horas: ISO 8601 com fuso (
2026-10-04T10:00:00-03:00). - Documentos: CPF, CNPJ, CEP e telefone aceitam máscara (
529.982.247-25): a API remove. O CNPJ pode ser alfanumérico (formato vigente desde julho de 2026). - Códigos com zero à esquerda (
codigo_ncm,forma_pagamento01, CST00) podem ser enviados como texto ou como número:4011000vira04011000. - Campos desconhecidos são recusados com
422e o caminho do campo. Digitação errada nunca vira dado ignorado em silêncio. As exceções (campos aceitos e ignorados de propósito) estão em Emitir NF-e. - Identificadores: a empresa é identificada pelo CNPJ na URL e pelo
id(uuid) nas respostas; o produto pelo SKU; a nota pelaref. Os ids numéricos internos não aparecem.
Compatibilidade
A versão está na URL (/api/v2). Dentro da v2 só adicionamos: campos novos em respostas, endpoints novos, valores novos de enumerações (status, evento...). Seu cliente deve ignorar campos que não conhece e tratar um status desconhecido como "não final". Mudanças que quebram contrato só entram em uma versão nova, com aviso prévio. Veja Novidades.