Pular para o conteúdo
VigiaXML
Desenvolvedores

Documentação da API VigiaXML

REST, JSON, autenticação via header X-Api-Key. Consulta NF-e, CT-e, MDF-e direto na SEFAZ. Monitoramento de 30 dias por chave. Importação de lotes mistos. Exemplos cURL e TypeScript prontos pra colar.

Base URL: https://api.vigiaxml.com · Trial gratuito: 30 dias ou 5.000 consultas — o que vier primeiro.

Quickstart

Da chave à primeira consulta em 5 minutos

Cadastre-se em /cadastro (1 min) → confirme o email → copie a api-key (mostrada uma única vez) → consulte. Trial gratuito não exige cartão.

quickstart.shbash
# 1. Exporte a api-key copiada após confirmar o email
export VIGIA_API_KEY="vxml_..."

# 2. Consulte uma chave (a API detecta o modelo pelas posições 21-22)
curl -X POST https://api.vigiaxml.com/v1/consulta \
  -H "X-Api-Key: $VIGIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "chaveAcesso": "35240300000000000000550010000001231123456785" }'

# 3. Coloque a mesma chave em monitoramento contínuo (30 dias)
curl -X POST https://api.vigiaxml.com/v1/monitoramento \
  -H "X-Api-Key: $VIGIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "chaveAcesso": "35240300000000000000550010000001231123456785",
    "callbackUrl": "https://erp.example.com/webhooks/vigia"
  }'
Cadastro

Sign-up self-service e api-key

POST/v1/auth/signupPOST/v1/auth/regenerate-api-key

O cadastro cria um tenant (sua carteira) + um user (o login do master) num só passo. Confirmação por email é obrigatória — sem ela, a api-key não é gerada. A chave plana aparece uma única vez na tela de confirmação. Se perder, gere outra via POST /v1/auth/regenerate-api-key (cookie de sessão) — a anterior é revogada.

cadastro.shbash
# 1. Cadastro self-service (não requer api-key)
curl -X POST https://api.vigiaxml.com/v1/auth/signup \
  -H "Content-Type: application/json" \
  -d '{
    "nomeUsuario": "Maria Souza",
    "nomeEmpresa": "Acme Factoring LTDA",
    "email": "maria@acme.com.br",
    "cnpj": "12345678000190",
    "senha": "uma-senha-forte-de-12-chars",
    "telefone": "11999990000",
    "aceiteTos": true
  }'

# Resposta 202 — independente de email já existir (anti-enumeração).
# Email de confirmação chega em segundos com link /verifique-email?token=...

# 2. Após confirmar pelo link, a tela mostra a api-key UMA ÚNICA VEZ.
# Você também pode girar a chave depois:
curl -X POST https://api.vigiaxml.com/v1/auth/regenerate-api-key \
  -H "Cookie: vxml_session=..." \
  -H "Content-Type: application/json"
Anti-enumeração: o endpoint sempre devolve 202 com a mesma mensagem, mesmo se o email/CNPJ já existir. Atacantes não conseguem mapear sua base de clientes.
Autenticação

API key por carteira (header X-Api-Key)

Cada api-key pertence a uma carteira (tenant). Chaves são prefixadas com vxml_ e armazenadas só como hash bcrypt — não temos como recuperar a chave plana depois.

Envie no header X-Api-Key: vxml_<sua-chave>. A API responde 401 se a chave for inválida ou tiver sido girada.

Existe também auth por cookie de sessão (vxml_session) usado pelo painel /conta — endpoints /v1/auth/login, /v1/auth/me, /v1/auth/logout, /v1/me/consulta, /v1/me/consultas. Para integração server-to-server use api-key.

Boa prática: nunca commit api-keys. Use variáveis de ambiente, secret manager (Azure Key Vault, AWS Secrets Manager) ou um cofre nativo do seu CI/CD.
Endpoint

Consulta avulsa

POST/v1/consultaconsome 1 unidade de consulta avulsa (R$ 0,20)

Faz uma chamada síncrona ao webservice da SEFAZ e devolve o status atual. Auto-detecta o modelo pelas posições 21-22 da chave: NF-e (55), CT-e (57), CT-e OS (67), MDF-e (58). Não cacheado — a resposta reflete o estado oficial naquele instante.

Body

CampoTipoDescrição
chaveAcessostring (obrig.)Chave de acesso de 44 dígitos. Aceita com hífens/espaços (são removidos).
consulta.shbash
curl -X POST https://api.vigiaxml.com/v1/consulta \
  -H "X-Api-Key: $VIGIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "chaveAcesso": "35240300000000000000550010000001231123456785"
  }'
consulta.tstypescript
const res = await fetch("https://api.vigiaxml.com/v1/consulta", {
  method: "POST",
  headers: {
    "X-Api-Key": process.env.VIGIA_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    chaveAcesso: "35240300000000000000550010000001231123456785",
  }),
});

if (!res.ok) throw new Error(`Consulta falhou: ${res.status}`);
const data = await res.json();
// data.status: "autorizada" | "cancelada" | "denegada" | "inexistente" | "outro" | "erro"
// data.c_stat: "100" | "101" | "217" | ...   (código oficial SEFAZ)
// data.x_motivo: mensagem oficial SEFAZ
// data.uf: "SP" | "MG" | ...
// data.modelo: "NF-e" | "CT-e" | "CT-e OS" | "MDF-e"
// data.modelo_codigo: 55 | 57 | 58 | 67
// data.duration_ms, data.queried_at, data.consulta_id

Resposta 200

response.jsonjson
{
  "consulta_id": "c5520f10-0511-425d-81b0-ffc75a81ca25",
  "chave_acesso": "35240300000000000000550010000001231123456785",
  "modelo": "NF-e",
  "modelo_codigo": 55,
  "uf": "SP",
  "status": "autorizada",
  "c_stat": "100",
  "x_motivo": "Autorizado o uso da NF-e",
  "situacao": "cStat=100 (consultar Anexo II do MOC NF-e)",
  "duration_ms": 1247,
  "queried_at": "2026-05-03T20:31:11.523Z"
}
Endpoint

Importação em lote

POST/v1/importaraté 1.000 chaves por request

Lote unificado — aceita NF-e + CT-e + MDF-e misturados no mesmo array. Modo avulsa só consulta. Modo monitoramento consulta E adiciona ao monitoramento contínuo de 30 dias. Para lotes grandes, use pularConsultaInline=true — a consulta inicial fica a cargo do worker (até 1h após enfileirar).

importar.shbash
# Lote misto (NF-e + CT-e + MDF-e) — modelo detectado pelas posições 21-22.
curl -X POST https://api.vigiaxml.com/v1/importar \
  -H "X-Api-Key: $VIGIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "chaves": [
      "35240300000000000000550010000001231123456785",
      "35240300000000000000570010000001231123456786",
      "35240300000000000000580010000001231123456787"
    ],
    "modo": "monitoramento",
    "webhookUrl": "https://erp.example.com/webhooks/vigia",
    "pularConsultaInline": false
  }'

Resposta 200

response.jsonjson
{
  "modo": "monitoramento",
  "total": 3,
  "duration_ms": 2918,
  "adicionadas": 3,
  "duplicadas": 0,
  "breakdown": { "nfe": 1, "cte": 1, "mdfe": 1 },
  "rejeitadas": [],
  "valor_estimado_brl": 1.05,
  "results": [
    { "chave": "35...", "modelo": 55, "tipo": "NF-e", "uf": "SP",
      "cStat": "100", "status": "autorizada", "xMotivo": "Autorizado o uso da NF-e", "durationMs": 980 }
  ]
}
Endpoints

Monitoramento contínuo (30 dias)

POST/v1/monitoramentoconsome 1 unidade de monitoramento (R$ 0,35)
GET/v1/monitoramentoGET/v1/monitoramento/:chaveDELETE/v1/monitoramento/:chave

Coloca a chave em vigilância automática. A cadência é horária no D0 (dia da emissão, onde concentra a maioria dos cancelamentos) e diária do D1 ao D30. A janela de 30 dias começa no momento do POST. DELETE é soft (encerra antecipadamente — o histórico fica preservado).

POST /v1/monitoramento — body

CampoTipoDescrição
chaveAcessostring (obrig.)Chave de acesso de 44 dígitos. Modelos aceitos: 55, 57, 58, 67.
callbackUrlstring (https)URL pra receber webhooks (opcional). Se omitido, o monitoramento existe mas não notifica.
monitoramento.shbash
# Adicionar uma chave ao monitoramento contínuo (vale 30 dias).
curl -X POST https://api.vigiaxml.com/v1/monitoramento \
  -H "X-Api-Key: $VIGIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "chaveAcesso": "35240300000000000000550010000001231123456785",
    "callbackUrl": "https://erp.example.com/webhooks/vigia"
  }'

# Listar carteira (paginado)
curl "https://api.vigiaxml.com/v1/monitoramento?ativos=true&limit=50&offset=0" \
  -H "X-Api-Key: $VIGIA_API_KEY"

# Detalhe de uma chave
curl https://api.vigiaxml.com/v1/monitoramento/35240300000000000000550010000001231123456785 \
  -H "X-Api-Key: $VIGIA_API_KEY"

# Encerrar antecipadamente (soft delete — para o polling)
curl -X DELETE https://api.vigiaxml.com/v1/monitoramento/35240300000000000000550010000001231123456785 \
  -H "X-Api-Key: $VIGIA_API_KEY"

Resposta 201 (POST) / 200 (GET detalhe)

response.jsonjson
{
  "id": "5e1d8a64-2c4f-4a3a-9ae8-5a0fbb2c9871",
  "chave": "35240300000000000000550010000001231123456785",
  "modelo": 55,
  "callback_url": "https://erp.example.com/webhooks/vigia",
  "status_atual": "autorizada",
  "criado_em": "2026-05-04T20:33:02Z",
  "expira_em": "2026-06-03T20:33:02Z",
  "proxima_consulta_em": "2026-05-04T21:33:02Z"
}
Dedup automático: tentar adicionar a mesma chave 2x na mesma janela retorna 409 conflict com o monitoramento existente. Use GET /v1/monitoramento/:chave se precisar do estado atual.
Endpoint

Histórico de consultas

GET/v1/consultas

Lista paginada de todas as consultas que sua carteira já fez (avulsas + as do monitoramento). Útil pra reconciliação caso o webhook tenha ficado off ou pra auditoria/relatório.

Query params

ParamTipoDefaultDescrição
chavestringFiltrar por uma chave específica (44 dígitos).
sinceISO 8601Apenas consultas com queried_at ≥ valor.
limitint (1-200)50Tamanho da página.
offsetint0Pular N resultados (paginação simples).
consultas.shbash
# Histórico paginado de consultas (mais recentes primeiro).
# Filtros: chave, since (ISO 8601), limit (max 200), offset.
curl "https://api.vigiaxml.com/v1/consultas?since=2026-05-01T00:00:00Z&limit=50" \
  -H "X-Api-Key: $VIGIA_API_KEY"
Endpoint

Eventos vinculados

GET/v1/eventos

Lista eventos que vieram acoplados às consultas: CCe (110110), Cancelamento (110111), Manifestação Destinatário (210200/210210/210220/210240), Passagem (310620 CT-e), Encerramento (110112 MDF-e), e outros. Use tp=210240 pra detectar duplicatas frias (destinatário declarando que não fez a operação).

eventos.shbash
# Eventos vinculados (CCe, manifestação, passagem, encerramento, etc).
# Filtros: chave, tp (tipo do evento), since, limit, offset.
curl "https://api.vigiaxml.com/v1/eventos?tp=210240&since=2026-05-01T00:00:00Z" \
  -H "X-Api-Key: $VIGIA_API_KEY"

Resposta

response.jsonjson
{
  "total": 2,
  "offset": 0,
  "limit": 50,
  "items": [
    {
      "id": "uuid",
      "chave_acesso": "35...",
      "tp_evento": "210240",
      "descricao": "Operação não Realizada",
      "n_seq_evento": 1,
      "dh_evento": "2026-05-04T18:21:09Z",
      "dh_reg_evento": "2026-05-04T18:21:11Z",
      "cnpj_autor": "12345678000190",
      "detalhe": "duplicata fria (manifestação 210240)",
      "protocolo": "135260000123456",
      "captured_at": "2026-05-04T19:00:00Z"
    }
  ]
}
Endpoint

Rastreio cross-document

GET/v1/rastreio/:chave

Dado uma chave (NF-e, CT-e ou MDF-e), devolve a árvore completa de documentos vinculados via eventos + linha do tempo cronológica. Útil pra reconstruir a história fiscal de uma operação: NF-e → CT-e (transportadora) → MDF-e (encerramento + condutor). Restrito ao escopo do tenant — não vaza chaves de outras carteiras.

rastreio.shbash
# Árvore de documentos vinculados (NF-e ↔ CT-e ↔ MDF-e) com timeline.
# Use pra reconstruir a história completa de uma operação fiscal.
curl https://api.vigiaxml.com/v1/rastreio/35240300000000000000550010000001231123456785 \
  -H "X-Api-Key: $VIGIA_API_KEY"
Webhooks

Notificações pra seu endpoint

Quando você passa callbackUrl em POST /v1/monitoramento ou POST /v1/importar, postamos um JSON nessa URL quando o trabalho finaliza ou quando algo muda. Timeout: 10s. Retry: até 3 tentativas com backoff (5min, 10min, 15min).

Eventos disponíveis hoje

event_typeQuando dispara
job.concluidoJob de importação em lote finalizou. Inclui contadores de sucesso/erro e duração total.

Payload de exemplo

webhook.jsonjson
{
  "event_type": "job.concluido",
  "job_id": "5e1d8a64-2c4f-4a3a-9ae8-5a0fbb2c9871",
  "tenant_id": "uuid-da-carteira",
  "tipo": "importar",
  "total_chaves": 200,
  "sucesso": 198,
  "erro": 2,
  "started_at": "2026-05-04T20:31:00Z",
  "finished_at": "2026-05-04T20:33:18Z",
  "duration_seconds": 138.4
}

Idempotência

Use job_idcomo chave de dedup. Mesmo job pode chegar 2x se sua resposta demorar > 10s.

Retry

Não-2xx ou timeout (10s) → backoff em minutos (5, 10, 15). Após 3 tentativas desistimos — o erro fica visível no painel.

Roadmap: webhook por mudança de status no monitoramento (nota.status_alterado) e assinatura HMAC-SHA256 do payload entram no Q2 2026. Hoje, valide a fonte por IP allowlist ou token na URL.
Erros

Códigos e como reagir

Toda resposta de erro é JSON com pelo menos o campo error:

error.jsonjson
{
  "error": "chave_acesso deve ter 44 dígitos"
}
CasoHTTPSignificadoO que fazer
invalid_request400Payload malformado, campo faltando ou chave de acesso inválida.Confira o body. Chave deve ter exatamente 44 dígitos.
unauthenticated401Header X-Api-Key ausente, mal formatado ou revogado.Verifique o header. Gere uma chave nova em /conta/api-key se necessário.
trial_expired402Trial gratuito expirou (30 dias) ou bateu o teto de 5.000 consultas.Contate vendas pra liberar plano pago.
not_found404Chave não está em monitoramento nessa carteira ou recurso não existe.Verifique se a chave foi de fato adicionada ao seu tenant.
conflict409Chave já está em monitoramento ativo nessa carteira.Use GET /v1/monitoramento/:chave pra ver o estado existente.
modelo_nao_suportado400Modelo da chave (posições 21-22) não está em (55, 57, 58, 67).Hoje suportamos NF-e (55), CT-e (57), CT-e OS (67) e MDF-e (58).
sefaz_unavailable503Pool de certificados sem capacidade ou SEFAZ off.Aguarde alguns minutos e tente novamente.
internal_error500Falha interna do VigiaXML.Repetir com backoff. Persistindo, escreva para suporte.
Rate limits

Limites por carteira

Limite por API key. O default é de 60 req/min (configurável em RateLimitConsultasMin). Volume maior é negociado — fale com vendas.

Trial: além do rate limit, contas em trial (signup self-service) têm teto adicional de 5.000 consultas em 30 dias. Quando bate, a API devolve 402 trial_expired até o admin liberar plano pago.

Pronto para o primeiro deploy?

Cadastre-se em 1 minuto, confirme o email e dispare a primeira consulta sem cartão de crédito. Trial de 30 dias / 5.000 consultas.