Developers/Documentação da API/API de Serviços

API de Serviços

CRUD completo de serviços via API. Gerencie cadastro de serviços com código municipal e NBS.

13/02/202612 min de leitura1 visualizações

Gerencie o cadastro de serviços do Bunto ERP. Este endpoint permite listar, consultar, criar, atualizar e excluir serviços da sua empresa via API.

Base URL

Produção:

https://api-backend.bunto.com.br/v1/servicos/

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: servicos com a ação correspondente (read, write ou delete).


Endpoints

Listar Serviços

GET /v1/servicos/

Escopo necessário: servicos: read

Retorna a lista paginada de serviços da empresa.

Query Parameters

ParâmetroTipoPadrãoDescrição
paginainteger1Número da página
por_paginainteger25Registros por página (máximo: 100)
buscastring-Busca por descrição ou código
situacaostring-Filtrar por situação: A (ativo), I (inativo)
ordenarstringdescricaoCampo de ordenação: descricao, codigo, preco
direcaostringascDireção da ordenação: asc ou desc

Exemplo com cURL

bash
curl 'https://api-backend.bunto.com.br/v1/servicos/?pagina=1&por_pagina=10&busca=consultoria&ordenar=preco&direcao=desc' \ -H 'Authorization: Bearer bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4' \ -H 'Content-Type: application/json'

Exemplo com Python

python
import requests BASE_URL = "https://api-backend.bunto.com.br/v1" TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4" headers = { "Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json", } # Listar servicos com filtros resposta = requests.get( f"{BASE_URL}/servicos/", headers=headers, params={ "pagina": 1, "por_pagina": 25, "situacao":"A", "ordenar": "descricao", "direcao": "asc", }, ) dados = resposta.json() if dados["success"]: servicos = dados["data"]["resultados"] paginacao = dados["data"]["paginacao"] print(f"Total de servicos: {paginacao['total_registros']}") for servico in servicos: print(f" - [{servico['codigo']}] {servico['descricao']} - R$ {servico['preco']}") else: print(f"Erro: {resposta.status_code}")

Exemplo com JavaScript

javascript
const BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const params = new URLSearchParams({ pagina: "1", por_pagina: "25", situacao: "A", ordenar: "descricao", direcao: "asc", }); const resposta = await fetch(`${BASE_URL}/servicos/?${params}`, { headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, }); const dados = await resposta.json(); if (dados.success) { const servicos = dados.data.resultados; const paginacao = dados.data.paginacao; console.log(`Total de servicos: ${paginacao.total_registros}`); servicos.forEach((servico) => { console.log(` - [${servico.codigo}] ${servico.descricao} - R$ ${servico.preco}`); }); } else { console.error(`Erro: ${resposta.status}`); }

Resposta (200 OK)

json
{ "success": true, "message": "38 registros encontrados", "data": { "resultados": [ { "id": 1, "descricao":"Consultoria em Gestão Empresarial", "codigo":"SERV-001", "preco":"250.00", "unidade": "HR", "situacao":"A", "situacao_display": "Ativo" }, { "id": 2, "descricao":"Manutencao Preventiva de Equipamentos", "codigo":"SERV-002", "preco":"180.00", "unidade": "UN", "situacao":"A", "situacao_display": "Ativo" } ], "paginacao": { "pagina_atual": 1, "total_paginas": 2, "total_registros": 38, "por_pagina": 25, "proxima": "https://api-backend.bunto.com.br/v1/servicos/?pagina=2", "anterior": null } } }

Campos da Listagem

CampoTipoDescrição
idintegerIdentificador único do serviço
descricaostringDescrição do serviço
codigostring / nullCódigo do serviço
precodecimalPreço do serviço
unidadestring / nullUnidade de medida (HR, UN, etc.)
situacaostringSituação: A (ativo), I (inativo)
situacao_displaystringDescrição legível da situação (ex.: "Ativo", "Inativo")

Obter Serviço

GET /v1/servicos/{id}/

Escopo necessário: servicos: read

Retorna os dados completos de um serviço específico, incluindo códigos fiscais e informações complementares.

Exemplo com cURL

bash
curl https://api-backend.bunto.com.br/v1/servicos/1/ \ -H 'Authorization: Bearer bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4' \ -H 'Content-Type: application/json'

Exemplo com Python

python
import requests BASE_URL = "https://api-backend.bunto.com.br/v1" TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4" headers = { "Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json", } servico_id = 1 resposta = requests.get(f"{BASE_URL}/servicos/{servico_id}/", headers=headers) dados = resposta.json() if dados["success"]: servico = dados["data"] print(f"Servico: {servico['descricao']}") print(f"Preco: R$ {servico['preco']}") if servico["codigo_servico_municipal"]: print(f"Codigo Municipal: {servico['codigo_servico_municipal']}") else: print(f"Erro: {dados}")

Exemplo com JavaScript

javascript
const BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const servicoId = 1; const resposta = await fetch(`${BASE_URL}/servicos/${servicoId}/`, { headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, }); const dados = await resposta.json(); if (dados.success) { const servico = dados.data; console.log(`Servico: ${servico.descricao}`); console.log(`Preco: R$ ${servico.preco}`); if (servico.codigo_servico_municipal) { console.log(`Codigo Municipal: ${servico.codigo_servico_municipal}`); } } else { console.error(`Erro: ${JSON.stringify(dados)}`); }

Resposta (200 OK)

json
{ "success": true, "message": "Registro encontrado", "data": { "id": 1, "descricao":"Consultoria em Gestão Empresarial", "codigo":"SERV-001", "preco":"250.00", "unidade": "HR", "situacao":"A", "situacao_display": "Ativo", "codigo_servico_municipal": "17.01", "nbs_codigo": "1.1301", "descricao_complementar": "Servico de consultoria especializada em processos de gestão, planejamento estratégico e otimização de recursos empresariais.", "observacoes":"Valor por hora. Minimo de 4 horas por contratação.", "criado_em": "2026-01-10T09:00:00-03:00", "atualizado_em": "2026-02-08T11:30:00-03:00" } }

Campos do Detalhe (adicionais à listagem)

CampoTipoDescrição
codigo_servico_municipalstring / nullCódigo do serviço na lista municipal (LC 116/2003)
nbs_codigostring / nullCódigo NBS (Nomenclatura Brasileira de Serviços)
descricao_complementarstring / nullDescrição complementar detalhada do serviço
observacoesstring / nullObservações internas
criado_emdatetimeData e hora de criação
atualizado_emdatetimeData e hora da última atualização

Criar Serviço

POST /v1/servicos/

Escopo necessário: servicos: write

Cria um novo serviço na empresa do token autenticado.

Importante: O par (empresa, codigo) é único. Dois serviços da mesma empresa não podem ter o mesmo codigo. Se você tentar criar um serviço com um código já existente, a API retornará erro de validação.

Campos do Request Body

CampoTipoObrigatórioDescrição
descricaostringSimDescrição do serviço (máximo 255 caracteres)
codigostringNãoCódigo do serviço (máximo 50 caracteres). Único por empresa
precodecimalNãoPreço do serviço (padrão: 0)
unidadestringNãoUnidade de medida (máximo 20 caracteres)
situacaostringNãoSituação: A (ativo, padrão), I (inativo)
codigo_servico_municipalstringNãoCódigo do serviço municipal (máximo 40 caracteres)
nbs_codigostringNãoCódigo NBS (máximo 20 caracteres)
descricao_complementarstringNãoDescrição complementar detalhada
observacoesstringNãoObservações internas

Exemplo com cURL

bash
curl -X POST https://api-backend.bunto.com.br/v1/servicos/ \ -H 'Authorization: Bearer bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4' \ -H 'Content-Type: application/json' \ -d '{ "descricao":"Desenvolvimento de Software Sob Demanda", "codigo":"SERV-039", "preco":180.00, "unidade": "HR", "situacao":"A", "codigo_servico_municipal": "01.01", "nbs_codigo": "1.1201", "descricao_complementar": "Desenvolvimento de sistemas web e aplicativos sob medida, incluindo levantamento de requisitos, codificação, testes e implantação.", "observacoes":"Valor por hora técnica. Projetos acima de 200 horas possuem desconto progressivo." }'

Exemplo com Python

python
import requests BASE_URL = "https://api-backend.bunto.com.br/v1" TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4" headers = { "Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json", } novo_servico = { "descricao":"Desenvolvimento de Software Sob Demanda", "codigo":"SERV-039", "preco":180.00, "unidade": "HR", "situacao":"A", "codigo_servico_municipal": "01.01", "nbs_codigo": "1.1201", "descricao_complementar": "Desenvolvimento de sistemas web e aplicativos sob medida, incluindo levantamento de requisitos, codificação, testes e implantação.", "observacoes":"Valor por hora técnica. Projetos acima de 200 horas possuem desconto progressivo.", } resposta = requests.post(f"{BASE_URL}/servicos/", headers=headers, json=novo_servico) dados = resposta.json() if dados["success"]: servico = dados["data"] print(f"Servico criado com sucesso! ID: {servico['id']}") print(f"Descricao: {servico['descricao']}") else: print(f"Erro ao criar servico: {dados}")

Exemplo com JavaScript

javascript
const BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const novoServico = { descricao: "Desenvolvimento de Software Sob Demanda", codigo: "SERV-039", preco: 180.0, unidade: "HR", situacao: "A", codigo_servico_municipal: "01.01", nbs_codigo: "1.1201", descricao_complementar: "Desenvolvimento de sistemas web e aplicativos sob medida, incluindo levantamento de requisitos, codificação, testes e implantação.", observacoes: "Valor por hora técnica. Projetos acima de 200 horas possuem desconto progressivo.", }; const resposta = await fetch(`${BASE_URL}/servicos/`, { method: "POST", headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify(novoServico), }); const dados = await resposta.json(); if (dados.success) { console.log(`Servico criado com sucesso! ID: ${dados.data.id}`); console.log(`Descricao: ${dados.data.descricao}`); } else { console.error(`Erro ao criar servico:`, dados); }

Resposta (201 Created)

json
{ "success": true, "message": "Servico criado com sucesso", "data": { "id": 39, "descricao":"Desenvolvimento de Software Sob Demanda", "codigo":"SERV-039", "preco":"180.00", "unidade": "HR", "situacao":"A", "situacao_display": "Ativo", "codigo_servico_municipal": "01.01", "nbs_codigo": "1.1201", "descricao_complementar": "Desenvolvimento de sistemas web e aplicativos sob medida, incluindo levantamento de requisitos, codificação, testes e implantação.", "observacoes":"Valor por hora técnica. Projetos acima de 200 horas possuem desconto progressivo.", "criado_em": "2026-02-12T15:30:00-03:00", "atualizado_em": "2026-02-12T15:30:00-03:00" } }

Atualizar Serviço

PUT /v1/servicos/{id}/
PATCH /v1/servicos/{id}/

Escopo necessário: servicos: write

Atualiza um serviço 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)

bash
curl -X PATCH https://api-backend.bunto.com.br/v1/servicos/39/ \ -H 'Authorization: Bearer bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4' \ -H 'Content-Type: application/json' \ -d '{ "preco":200.00, "descricao_complementar": "Desenvolvimento de sistemas web e aplicativos sob medida, incluindo levantamento de requisitos, codificação, testes, implantação e suporte pós-entrega por 30 dias." }'

Exemplo com Python

python
import requests BASE_URL = "https://api-backend.bunto.com.br/v1" TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4" headers = { "Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json", } servico_id = 39 # Atualizacao parcial (PATCH) - apenas os campos que mudaram atualizacao = { "preco":200.00, "descricao_complementar": "Desenvolvimento de sistemas web e aplicativos sob medida, incluindo levantamento de requisitos, codificação, testes, implantação e suporte pós-entrega por 30 dias.", } resposta = requests.patch( f"{BASE_URL}/servicos/{servico_id}/", headers=headers, json=atualizacao, ) dados = resposta.json() if dados["success"]: servico = dados["data"] print(f"Servico atualizado! Novo preco: R$ {servico['preco']}") else: print(f"Erro ao atualizar: {dados}")

Exemplo com JavaScript

javascript
const BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const servicoId = 39; const atualizacao = { preco: 200.0, descricao_complementar: "Desenvolvimento de sistemas web e aplicativos sob medida, incluindo levantamento de requisitos, codificação, testes, implantação e suporte pós-entrega por 30 dias.", }; const resposta = await fetch(`${BASE_URL}/servicos/${servicoId}/`, { method: "PATCH", headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify(atualizacao), }); const dados = await resposta.json(); if (dados.success) { console.log(`Servico atualizado! Novo preco: R$ ${dados.data.preco}`); } else { console.error(`Erro ao atualizar:`, dados); }

Resposta (200 OK)

json
{ "success": true, "message": "Servico atualizado com sucesso", "data": { "id": 39, "descricao":"Desenvolvimento de Software Sob Demanda", "codigo":"SERV-039", "preco":"200.00", "unidade": "HR", "situacao":"A", "situacao_display": "Ativo", "codigo_servico_municipal": "01.01", "nbs_codigo": "1.1201", "descricao_complementar": "Desenvolvimento de sistemas web e aplicativos sob medida, incluindo levantamento de requisitos, codificação, testes, implantação e suporte pós-entrega por 30 dias.", "observacoes":"Valor por hora técnica. Projetos acima de 200 horas possuem desconto progressivo.", "criado_em": "2026-02-12T15:30:00-03:00", "atualizado_em": "2026-02-12T16:45:00-03:00" } }

Excluir Serviço (Soft Delete)

DELETE /v1/servicos/{id}/

Escopo necessário: servicos: delete

Inativa o serviço (soft delete). O registro não é removido permanentemente do banco de dados -- o campo situacao é definido como I (inativo), preservando o histórico de utilização.

Exemplo com cURL

bash
curl -X DELETE https://api-backend.bunto.com.br/v1/servicos/39/ \ -H 'Authorization: Bearer bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4'

Exemplo com Python

python
import requests BASE_URL = "https://api-backend.bunto.com.br/v1" TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4" headers = {"Authorization": f"Bearer {TOKEN}"} servico_id = 39 resposta = requests.delete(f"{BASE_URL}/servicos/{servico_id}/", headers=headers) dados = resposta.json() if dados["success"]: print("Servico excluído com sucesso!") else: print(f"Erro ao excluir: {dados}")

Exemplo com JavaScript

javascript
const BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const servicoId = 39; const resposta = await fetch(`${BASE_URL}/servicos/${servicoId}/`, { method: "DELETE", headers: { Authorization: `Bearer ${TOKEN}`, }, }); const dados = await resposta.json(); if (dados.success) { console.log("Servico excluído com sucesso!"); } else { console.error(`Erro ao excluir:`, dados); }

Resposta (200 OK)

json
{ "success": true, "message": "Registro excluído com sucesso" }

Importante: Serviços excluídos via soft delete têm a situação alterada para I (inativo). Para visualizar serviços inativos, filtre por situacao=I.


Erros Comuns

CódigoErroCausaSolução
400VALIDATION_ERRORDados enviados são inválidos (campo obrigatório ausente, formato incorreto, código duplicado, etc.)Verifique os campos obrigatórios e os tipos de dados
401Token invalidoToken ausente, expirado, revogado ou mal formatadoVerifique se o header é Authorization: Bearer bnt_xxx
403Token nao tem permissaoO token não possui o escopo servicos ou a ação necessária (read, write, delete)Verifique os escopos do token no painel
404Nao encontradoServiço não existe ou pertence a outra empresaConfirme o ID e se o serviço pertence à empresa do token
429Limite de requisicoes excedidoRate limit ultrapassado para o tipo de operaçãoImplemente retry com backoff exponencial

Exemplo de Resposta de Erro (400 - Validação)

json
{ "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Erro de validacao", "details": { "descricao": ["Este campo é obrigatorio."], "codigo": ["Servico com este codigo ja existe nesta empresa."] } } }

Exemplo de Resposta de Erro (403 - Permissão)

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çãoMétodos HTTPLimite
LeituraGET, HEAD, OPTIONS120 requisições/minuto
EscritaPOST, PUT, PATCH30 requisições/minuto
ExclusãoDELETE10 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=100 para reduzir o número de requisições ao listar serviços
  • Implemente retry com backoff exponencial ao receber 429
  • Armazene dados em cache local quando possível
  • Para atualizações em lote, use PATCH apenas com os campos alterados para economizar requisições de escrita

Paginação

Todos os endpoints de listagem retornam dados paginados.

Parâmetros

ParâmetroTipoPadrãoMáximoDescrição
paginainteger1-Número da página
por_paginainteger25100Registros 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

CampoTipoDescrição
pagina_atualintegerNúmero da página atual
total_paginasintegerTotal de páginas disponíveis
total_registrosintegerTotal de registros encontrados
por_paginaintegerRegistros por página
proximastring / nullURL da próxima página (null se for a última)
anteriorstring / nullURL da página anterior (null se for a primeira)

Exemplo: percorrer todas as páginas (Python)

python
import requests BASE_URL = "https://api-backend.bunto.com.br/v1" TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4" headers = {"Authorization": f"Bearer {TOKEN}"} todos_os_servicos = [] url = f"{BASE_URL}/servicos/?por_pagina=100" while url: resposta = requests.get(url, headers=headers) dados = resposta.json() if not dados["success"]: break todos_os_servicos.extend(dados["data"]["resultados"]) url = dados["data"]["paginacao"]["proxima"] print(f"Total obtido: {len(todos_os_servicos)} servicos")

Valores de Referência

Situação do Serviço

ValorDescrição
AAtivo
IInativo (inclui serviços excluídos via soft delete)
APICRUDcURLJavaScriptPythonRESTServiços
Recursos para IA