API de Naturezas
CRUD de naturezas de operação fiscal via API.
Gerencie as naturezas de operação do Bunto ERP. Este endpoint permite listar, consultar, criar, atualizar e excluir naturezas que definem regras fiscais (CFOP, CRT, impostos) para operações de entrada e saída via API.
Base URL
Produção:
https://api-backend.bunto.com.br/v1/naturezas/
Autenticação
Todas as requisições exigem um Token de API no header Authorization:
Authorization: Bearer bnt_seu_token_aqui
Tokens são gerados em Integrações -> Tokens de API no painel do Bunto ERP. Escopo necessário: naturezas com a ação correspondente (read, write ou delete).
Endpoints
Listar Naturezas
GET /v1/naturezas/
Escopo necessário: naturezas: read
Retorna a lista paginada de naturezas de operação da empresa. Por padrão, apenas naturezas ativas (situação = 1) são retornadas.
Query Parameters
| Parâmetro | Tipo | Padrão | Descrição |
|---|---|---|---|
pagina | integer | 1 | Número da página |
por_pagina | integer | 25 | Registros por página (máximo: 100) |
busca | string | - | Busca por descrição ou CFOP |
tipo | string | - | Filtrar por tipo: S (Saída) ou E (Entrada) |
incluir_inativos | boolean | false | true para incluir naturezas inativas (situação = 0) |
ordenar | string | descricao | Campo de ordenação: descricao, cfop, tipo |
direcao | string | asc | Direção da ordenação: asc ou desc |
Exemplo com cURL
bashcurl 'https://api-backend.bunto.com.br/v1/naturezas/?pagina=1&por_pagina=10&tipo=S&ordenar=descricao&direcao=asc' \ -H 'Authorization: Bearer bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4' \ -H 'Content-Type: application/json'
Exemplo com Python
pythonimport requests BASE_URL = "https://api-backend.bunto.com.br/v1" TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4" headers = { "Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json", } # Listar naturezas de saida ordenadas por descricao resposta = requests.get( f"{BASE_URL}/naturezas/", headers=headers, params={ "pagina": 1, "por_pagina": 25, "tipo": "S", "ordenar": "descricao", "direcao": "asc", }, ) dados = resposta.json() if dados["success"]: naturezas = dados["data"]["resultados"] paginacao = dados["data"]["paginacao"] print(f"Total de naturezas: {paginacao['total_registros']}") for natureza in naturezas: print(f" - {natureza['descricao']} (CFOP: {natureza['cfop']}, Tipo: {natureza['tipo']})") else: print(f"Erro: {resposta.status_code}")
Exemplo com JavaScript
javascriptconst BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const params = new URLSearchParams({ pagina: "1", por_pagina: "25", tipo: "S", ordenar: "descricao", direcao: "asc", }); const resposta = await fetch(`${BASE_URL}/naturezas/?${params}`, { headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, }); const dados = await resposta.json(); if (dados.success) { const naturezas = dados.data.resultados; const paginacao = dados.data.paginacao; console.log(`Total de naturezas: ${paginacao.total_registros}`); naturezas.forEach((natureza) => { console.log(` - ${natureza.descricao} (CFOP: ${natureza.cfop}, Tipo: ${natureza.tipo})`); }); } else { console.error(`Erro: ${resposta.status}`); }
Resposta (200 OK)
json{ "success": true, "message": "5 registros encontrados", "data": { "resultados": [ { "id": 1, "descricao":"Venda de mercadoria dentro do estado", "tipo": "S", "cfop": "5102", "crt": 1, "situacao":1, "padrao":"V" }, { "id": 2, "descricao":"Venda de mercadoria fora do estado", "tipo": "S", "cfop": "6102", "crt": 1, "situacao":1, "padrao":null }, { "id": 3, "descricao":"Devolucao de compra dentro do estado", "tipo": "S", "cfop": "5202", "crt": 1, "situacao":1, "padrao":null } ], "paginacao": { "pagina_atual": 1, "total_paginas": 1, "total_registros": 5, "por_pagina": 25, "proxima": null, "anterior": null } } }
Campos da Listagem
| Campo | Tipo | Descrição |
|---|---|---|
id | integer | Identificador único da natureza |
descricao | string | Descrição da natureza de operação |
tipo | string | Tipo da operação: S (Saída) ou E (Entrada) |
cfop | string / null | Código Fiscal de Operações e Prestações |
crt | integer | Código de Regime Tributário (1 = Simples Nacional, 2 = Simples Nacional - excesso, 3 = Regime Normal) |
situacao | integer | Status da natureza: 1 (ativa) ou 0 (inativa) |
padrao | string / null | Indica se é natureza padrão para alguma operação (ex: V para venda) |
Obter Natureza
GET /v1/naturezas/{id}/
Escopo necessário: naturezas: read
Retorna os dados completos de uma natureza específica, incluindo a lista de regras fiscais vinculadas.
Exemplo com cURL
bashcurl https://api-backend.bunto.com.br/v1/naturezas/1/ \ -H 'Authorization: Bearer bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4' \ -H 'Content-Type: application/json'
Exemplo com Python
pythonimport requests BASE_URL = "https://api-backend.bunto.com.br/v1" TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4" headers = { "Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json", } natureza_id = 1 resposta = requests.get(f"{BASE_URL}/naturezas/{natureza_id}/", headers=headers) dados = resposta.json() if dados["success"]: natureza = dados["data"] print(f"Natureza: {natureza['descricao']}") print(f"CFOP: {natureza['cfop']} | Tipo: {natureza['tipo']}") if natureza["regras"]: print("Regras fiscais:") for regra in natureza["regras"]: print(f" - {regra['imposto_descricao']}: {regra['aliquota']}% (ST: {regra['st']})") else: print(f"Erro: {dados}")
Exemplo com JavaScript
javascriptconst BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const naturezaId = 1; const resposta = await fetch(`${BASE_URL}/naturezas/${naturezaId}/`, { headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, }); const dados = await resposta.json(); if (dados.success) { const natureza = dados.data; console.log(`Natureza: ${natureza.descricao}`); console.log(`CFOP: ${natureza.cfop} | Tipo: ${natureza.tipo}`); if (natureza.regras && natureza.regras.length > 0) { console.log("Regras fiscais:"); natureza.regras.forEach((regra) => { console.log(` - ${regra.imposto_descricao}: ${regra.aliquota}% (ST: ${regra.st})`); }); } } else { console.error(`Erro: ${JSON.stringify(dados)}`); }
Resposta (200 OK)
json{ "success": true, "message": "Registro encontrado", "data": { "id": 1, "descricao":"Venda de mercadoria dentro do estado", "tipo": "S", "cfop": "5102", "crt": 1, "situacao":1, "padrao":"V", "obs": "Natureza padrao para vendas dentro do estado.", "data_criacao": "2026-01-10T09:00:00-03:00", "data_atualizacao": "2026-02-05T14:30:00-03:00", "regras": [ { "id": 10, "id_imposto": 1, "imposto_descricao": "ICMS", "aliquota": "18.0000", "base": "100.0000", "st": "00", "cfop": "5102", "ordem": 1 }, { "id": 11, "id_imposto": 2, "imposto_descricao": "PIS", "aliquota": "0.6500", "base": "100.0000", "st": "01", "cfop": null, "ordem": 2 }, { "id": 12, "id_imposto": 3, "imposto_descricao": "COFINS", "aliquota": "3.0000", "base": "100.0000", "st": "01", "cfop": null, "ordem": 3 } ] } }
Campos do Detalhe (adicionais à listagem)
| Campo | Tipo | Descrição |
|---|---|---|
obs | string / null | Observações da natureza |
data_criacao | datetime | Data e hora de criação |
data_atualizacao | datetime | Data e hora da última atualização |
regras | array | Lista de regras fiscais vinculadas |
Campos de cada regra fiscal
| Campo | Tipo | Descrição |
|---|---|---|
id | integer | Identificador da regra |
id_imposto | integer | ID do imposto |
imposto_descricao | string | Descrição do imposto (ex: ICMS, PIS, COFINS) |
aliquota | string (decimal) | Alíquota do imposto |
base | string (decimal) | Base de cálculo do imposto |
st | string | Situação tributária (CST/CSOSN) |
cfop | string / null | CFOP específico da regra (quando diferente da natureza) |
ordem | integer | Ordem de exibição da regra |
Criar Natureza
POST /v1/naturezas/
Escopo necessário: naturezas: write
Cria uma nova natureza de operação na empresa do token autenticado.
Campos do Request Body
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
descricao | string | Sim | Descrição da natureza (máximo 200 caracteres) |
tipo | string | Sim | Tipo de operação: S (Saída) ou E (Entrada) |
cfop | string | Não | Código Fiscal de Operações e Prestações (máximo 10 caracteres) |
crt | integer | Não | Código de Regime Tributário (padrão: 1) |
obs | string | Não | Observações |
padrao | string | Não | Indicador de natureza padrão (máximo 1 caractere) |
Exemplo com cURL
bashcurl -X POST https://api-backend.bunto.com.br/v1/naturezas/ \ -H 'Authorization: Bearer bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4' \ -H 'Content-Type: application/json' \ -d '{ "descricao":"Venda de producao do estabelecimento", "tipo": "S", "cfop": "5101", "crt": 1, "obs": "Para venda de produtos fabricados pela própria empresa." }'
Exemplo com Python
pythonimport requests BASE_URL = "https://api-backend.bunto.com.br/v1" TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4" headers = { "Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json", } nova_natureza = { "descricao":"Venda de producao do estabelecimento", "tipo": "S", "cfop": "5101", "crt": 1, "obs": "Para venda de produtos fabricados pela própria empresa.", } resposta = requests.post(f"{BASE_URL}/naturezas/", headers=headers, json=nova_natureza) dados = resposta.json() if dados["success"]: natureza = dados["data"] print(f"Natureza criada com sucesso! ID: {natureza['id']}") print(f"Descricao: {natureza['descricao']}") print(f"CFOP: {natureza['cfop']}") else: print(f"Erro ao criar natureza: {dados}")
Exemplo com JavaScript
javascriptconst BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const novaNatureza = { descricao: "Venda de producao do estabelecimento", tipo: "S", cfop: "5101", crt: 1, obs: "Para venda de produtos fabricados pela própria empresa.", }; const resposta = await fetch(`${BASE_URL}/naturezas/`, { method: "POST", headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify(novaNatureza), }); const dados = await resposta.json(); if (dados.success) { console.log(`Natureza criada com sucesso! ID: ${dados.data.id}`); console.log(`Descricao: ${dados.data.descricao}`); console.log(`CFOP: ${dados.data.cfop}`); } else { console.error(`Erro ao criar natureza:`, dados); }
Resposta (201 Created)
json{ "success": true, "message": "Natureza criada com sucesso", "data": { "id": 8, "descricao":"Venda de producao do estabelecimento", "tipo": "S", "cfop": "5101", "crt": 1, "situacao":1, "padrao":null, "obs": "Para venda de produtos fabricados pela própria empresa.", "data_criacao": "2026-02-12T15:30:00-03:00", "data_atualizacao": "2026-02-12T15:30:00-03:00", "regras": [] } }
Atualizar Natureza
PUT /v1/naturezas/{id}/
PATCH /v1/naturezas/{id}/
Escopo necessário: naturezas: write
Atualiza uma natureza existente. Use PUT para atualização completa ou PATCH para atualização parcial (apenas os campos enviados serão alterados).
Exemplo com cURL (PATCH - atualização parcial)
bashcurl -X PATCH https://api-backend.bunto.com.br/v1/naturezas/8/ \ -H 'Authorization: Bearer bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4' \ -H 'Content-Type: application/json' \ -d '{ "descricao":"Venda de producao própria - dentro do estado", "obs": "Atualizada para especificar operacao interna." }'
Exemplo com Python
pythonimport requests BASE_URL = "https://api-backend.bunto.com.br/v1" TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4" headers = { "Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json", } natureza_id = 8 # Atualizacao parcial (PATCH) - apenas os campos que mudaram atualizacao = { "descricao":"Venda de producao própria - dentro do estado", "obs": "Atualizada para especificar operacao interna.", } resposta = requests.patch( f"{BASE_URL}/naturezas/{natureza_id}/", headers=headers, json=atualizacao, ) dados = resposta.json() if dados["success"]: natureza = dados["data"] print(f"Natureza atualizada! Descricao: {natureza['descricao']}") print(f"CFOP: {natureza['cfop']}") else: print(f"Erro ao atualizar: {dados}")
Exemplo com JavaScript
javascriptconst BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const naturezaId = 8; const atualizacao = { descricao: "Venda de producao própria - dentro do estado", obs: "Atualizada para especificar operacao interna.", }; const resposta = await fetch(`${BASE_URL}/naturezas/${naturezaId}/`, { method: "PATCH", headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify(atualizacao), }); const dados = await resposta.json(); if (dados.success) { console.log(`Natureza atualizada! Descricao: ${dados.data.descricao}`); console.log(`CFOP: ${dados.data.cfop}`); } else { console.error(`Erro ao atualizar:`, dados); }
Resposta (200 OK)
json{ "success": true, "message": "Natureza atualizada com sucesso", "data": { "id": 8, "descricao":"Venda de producao própria - dentro do estado", "tipo": "S", "cfop": "5101", "crt": 1, "situacao":1, "padrao":null, "obs": "Atualizada para especificar operacao interna.", "data_criacao": "2026-02-12T15:30:00-03:00", "data_atualizacao": "2026-02-12T16:45:00-03:00", "regras": [] } }
Excluir Natureza (Soft Delete)
DELETE /v1/naturezas/{id}/
Escopo necessário: naturezas: delete
Desativa a natureza (soft delete). O registro não é removido permanentemente do banco de dados -- o campo situacao é definido como 0, preservando o histórico e os vínculos com notas fiscais.
Exemplo com cURL
bashcurl -X DELETE https://api-backend.bunto.com.br/v1/naturezas/8/ \ -H 'Authorization: Bearer bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4'
Exemplo com Python
pythonimport requests BASE_URL = "https://api-backend.bunto.com.br/v1" TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4" headers = {"Authorization": f"Bearer {TOKEN}"} natureza_id = 8 resposta = requests.delete(f"{BASE_URL}/naturezas/{natureza_id}/", headers=headers) dados = resposta.json() if dados["success"]: print("Natureza excluída com sucesso!") else: print(f"Erro ao excluir: {dados}")
Exemplo com JavaScript
javascriptconst BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const naturezaId = 8; const resposta = await fetch(`${BASE_URL}/naturezas/${naturezaId}/`, { method: "DELETE", headers: { Authorization: `Bearer ${TOKEN}`, }, }); const dados = await resposta.json(); if (dados.success) { console.log("Natureza excluída com sucesso!"); } else { console.error(`Erro ao excluir:`, dados); }
Resposta (200 OK)
json{ "success": true, "message": "Registro excluído com sucesso" }
Importante: Naturezas desativadas via soft delete (situacao=0) não aparecem nas listagens por padrão. Para visualizar naturezas inativas, use o parâmetro incluir_inativos=true.
Erros Comuns
| Código | Erro | Causa | Solução |
|---|---|---|---|
| 400 | VALIDATION_ERROR | Dados enviados são inválidos (campo obrigatório ausente, formato incorreto, etc.) | Verifique os campos obrigatórios e os tipos de dados |
| 401 | Token invalido | Token ausente, expirado, revogado ou mal formatado | Verifique se o header é Authorization: Bearer bnt_xxx |
| 403 | Token nao tem permissao | O token não possui o escopo naturezas ou a ação necessária (read, write, delete) | Verifique os escopos do token no painel |
| 404 | Nao encontrado | Natureza não existe ou pertence a outra empresa | Confirme o ID e se a natureza pertence à empresa do token |
| 429 | Limite de requisicoes excedido | Rate limit ultrapassado para o tipo de operação | Implemente retry com backoff exponencial |
Exemplo de Resposta de Erro (400)
json{ "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Erro de validacao", "details": { "descricao": ["Este campo é obrigatorio."], "tipo": ["\"X\" nao é uma opcao valida. Escolha entre: S, E."] } } }
Exemplo de Resposta de Erro (403)
json{ "detail": "Token nao tem permissao para este recurso" }
Rate Limiting
A API aplica limites de requisição por token (não por IP). Cada tipo de operação tem um limite diferente.
| Operação | Métodos HTTP | Limite |
|---|---|---|
| Leitura | GET, HEAD, OPTIONS | 120 requisições/minuto |
| Escrita | POST, PUT, PATCH | 30 requisições/minuto |
| Exclusão | DELETE | 10 requisições/minuto |
Ao exceder o limite, a API retorna 429 Too Many Requests:
json{ "detail": "Limite de requisicoes excedido. Tente novamente em 45 segundos." }
Boas práticas
- Use
por_pagina=100para reduzir o número de requisições ao listar naturezas - Implemente retry com backoff exponencial ao receber
429 - Armazene dados em cache local quando possível
- Para atualizações em lote, use
PATCHapenas com os campos alterados para economizar requisições de escrita
Paginação
Todos os endpoints de listagem retornam dados paginados.
Parâmetros
| Parâmetro | Tipo | Padrão | Máximo | Descrição |
|---|---|---|---|---|
pagina | integer | 1 | - | Número da página |
por_pagina | integer | 25 | 100 | Registros por página |
Atenção: Os parâmetros são pagina e por_pagina (em português), não page e per_page.
Objeto paginacao na resposta
| Campo | Tipo | Descrição |
|---|---|---|
pagina_atual | integer | Número da página atual |
total_paginas | integer | Total de páginas disponíveis |
total_registros | integer | Total de registros encontrados |
por_pagina | integer | Registros por página |
proxima | string / null | URL da próxima página (null se for a última) |
anterior | string / null | URL da página anterior (null se for a primeira) |
Exemplo: percorrer todas as páginas (Python)
pythonimport requests BASE_URL = "https://api-backend.bunto.com.br/v1" TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4" headers = {"Authorization": f"Bearer {TOKEN}"} todas_as_naturezas = [] url = f"{BASE_URL}/naturezas/?por_pagina=100" while url: resposta = requests.get(url, headers=headers) dados = resposta.json() if not dados["success"]: break todas_as_naturezas.extend(dados["data"]["resultados"]) url = dados["data"]["paginacao"]["proxima"] print(f"Total obtido: {len(todas_as_naturezas)} naturezas")