Developers/Documentação da API/API de Clientes

API de Clientes

CRUD completo de clientes via API. Gerencie cadastro de clientes com conformidade LGPD.

13/02/202618 min de leitura13 visualizações

Gerencie o cadastro de clientes da sua empresa via API. Consulte, crie, atualize e exclua registros de clientes de forma programática.


Visão Geral

PropriedadeValor
Base URL (produção)https://api-backend.bunto.com.br/v1/clientes/
AutenticaçãoAuthorization: Bearer bnt_xxx
FormatoJSON
Escopo necessário (leitura)clientes: read
Escopo necessário (escrita)clientes: write
Escopo necessário (exclusão)clientes: delete

Endpoints

MétodoEndpointDescriçãoEscopo
GET/v1/clientes/Listar clientesclientes: read
GET/v1/clientes/{id}/Detalhar clienteclientes: read
POST/v1/clientes/Criar clienteclientes: write
PUT/v1/clientes/{id}/Atualizar cliente (completo)clientes: write
PATCH/v1/clientes/{id}/Atualizar cliente (parcial)clientes: write
DELETE/v1/clientes/{id}/Excluir clienteclientes: delete

Proteção de Dados (LGPD)

O Bunto ERP segue a Lei Geral de Proteção de Dados (LGPD). Os campos sensíveis dos clientes recebem tratamento especial:

Campos criptografados

Os seguintes campos são armazenados de forma criptografada no banco de dados:

  • cnpj_cpf (CPF ou CNPJ)
  • email
  • celular
  • tel_fixo (telefone fixo)
  • rg
  • data_nascimento
  • cpf_pai, cpf_mae

Comportamento por endpoint

EndpointCampos sensíveis
Listagem (GET /clientes/)Não retornados - proteção contra exposição em massa
Detalhe (GET /clientes/{id}/)Descriptografados automaticamente e incluídos na resposta
Criação (POST /clientes/)Criptografados automaticamente antes de salvar no banco
Atualização (PUT/PATCH /clientes/{id}/)Criptografados automaticamente antes de salvar no banco

Importante: Na listagem, campos como CPF/CNPJ, e-mail e telefone não são retornados. Para acessar esses dados, utilize o endpoint de detalhe (GET /v1/clientes/{id}/).


Listar Clientes

GET /v1/clientes/

Retorna uma lista paginada de clientes da empresa. Por segurança (LGPD), campos sensíveis como CPF/CNPJ, e-mail e telefone não são incluídos na listagem.

Parâmetros de consulta

ParâmetroTipoDescrição
buscastringBusca por nome ou nome fantasia
tipo_pessoaintegerFiltrar por tipo: 1 = Pessoa Física, 2 = Pessoa Jurídica
cidadestringFiltrar por cidade (busca parcial, case-insensitive)
ufstringFiltrar por UF (2 caracteres, ex: SP, RJ)
ordenarstringCampo de ordenação: nome, cidade, uf
direcaostringDireção da ordenação: asc (padrão) ou desc
paginaintegerNúmero da página (padrão: 1)
por_paginaintegerRegistros por página (padrão: 25, máximo: 100)

Campos retornados na listagem

CampoTipoDescrição
idintegerID único do cliente
nomestringNome completo ou razão social
fantasiastring ou nullNome fantasia
codigostring ou nullCódigo interno do cliente
tipo_pessoainteger1 = Pessoa Física, 2 = Pessoa Jurídica
tipo_pessoa_labelstringLabel legível: "Pessoa Física" ou "Pessoa Jurídica"
consumidor_finalbooleanIndica se é o consumidor final padrão da empresa
cidadestring ou nullCidade do cliente
ufstring ou nullUnidade federativa (2 caracteres)

Exemplo com cURL

bash
curl 'https://api-backend.bunto.com.br/v1/clientes/?busca=silva&tipo_pessoa=1&uf=SP&por_pagina=10' \ -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 clientes pessoa física de Sao Paulo resposta = requests.get( f"{BASE_URL}/clientes/", headers=headers, params={ "tipo_pessoa": 1, "uf": "SP", "ordenar": "nome", "direcao": "asc", "por_pagina": 25, }, ) dados = resposta.json() if dados["success"]: clientes = dados["data"]["resultados"] paginacao = dados["data"]["paginacao"] print(f"Total de clientes: {paginacao['total_registros']}") for cliente in clientes: print(f" - {cliente['nome']} ({cliente['tipo_pessoa_label']}) - {cliente['cidade']}/{cliente['uf']}") else: print(f"Erro: {dados}")

Exemplo com JavaScript

javascript
const BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const params = new URLSearchParams({ tipo_pessoa: "1", uf: "SP", ordenar: "nome", direcao: "asc", por_pagina: "25", }); const resposta = await fetch(`${BASE_URL}/clientes/?${params}`, { headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, }); const dados = await resposta.json(); if (dados.success) { const clientes = dados.data.resultados; const paginacao = dados.data.paginacao; console.log(`Total de clientes: ${paginacao.total_registros}`); clientes.forEach((cliente) => { console.log(` - ${cliente.nome} (${cliente.tipo_pessoa_label}) - ${cliente.cidade}/${cliente.uf}`); }); }

Resposta de sucesso (200)

json
{ "success": true, "message": "47 registros encontrados", "data": { "resultados": [ { "id": 142, "nome": "Ana Carolina da Silva", "fantasia": null, "codigo":"CLI-0142", "tipo_pessoa": 1, "tipo_pessoa_label": "Pessoa Física", "consumidor_final": false, "cidade": "Sao Paulo", "uf": "SP" }, { "id": 87, "nome": "Distribuidora Santos Ltda", "fantasia": "Santos Distribuidora", "codigo":"CLI-0087", "tipo_pessoa": 2, "tipo_pessoa_label": "Pessoa Jurídica", "consumidor_final": false, "cidade": "Campinas", "uf": "SP" } ], "paginacao": { "pagina_atual": 1, "total_paginas": 2, "total_registros": 47, "por_pagina": 25, "proxima": "https://api-backend.bunto.com.br/v1/clientes/?pagina=2&por_pagina=25&uf=SP", "anterior": null } } }

Detalhar Cliente

GET /v1/clientes/{id}/

Retorna todos os dados de um cliente, incluindo campos sensíveis descriptografados (CPF/CNPJ, e-mail, telefone, etc.).

Parâmetros de rota

ParâmetroTipoDescrição
idintegerID do cliente

Campos retornados no detalhe

Além de todos os campos da listagem, o detalhe inclui:

CampoTipoDescriçãoLGPD
cnpj_cpfstring ou nullCPF (Pessoa Física) ou CNPJ (Pessoa Jurídica)Sim
emailstring ou nullE-mail do clienteSim
celularstring ou nullNúmero do celularSim
tel_fixostring ou nullNúmero do telefone fixoSim
cepstring ou nullCEP do endereço principalNão
enderecostring ou nullLogradouroNão
numerostring ou nullNúmero do endereçoNão
complementostring ou nullComplemento do endereçoNão
bairrostring ou nullBairroNão
insc_estadualstring ou nullInscrição estadualNão
ie_isentobooleanIndica se é isento de inscrição estadualNão
limite_creditodecimal ou nullLimite de crédito em R$Não
observacoesstring ou nullObservações geraisNão

Exemplo com cURL

bash
curl https://api-backend.bunto.com.br/v1/clientes/142/ \ -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", } resposta = requests.get(f"{BASE_URL}/clientes/142/", headers=headers) dados = resposta.json() if dados["success"]: cliente = dados["data"] print(f"Nome: {cliente['nome']}") print(f"CPF/CNPJ: {cliente['cnpj_cpf']}") print(f"E-mail: {cliente['email']}") print(f"Celular: {cliente['celular']}") print(f"Cidade: {cliente['cidade']}/{cliente['uf']}") else: print(f"Erro: {dados}")

Exemplo com JavaScript

javascript
const BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const resposta = await fetch(`${BASE_URL}/clientes/142/`, { headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, }); const dados = await resposta.json(); if (dados.success) { const cliente = dados.data; console.log(`Nome: ${cliente.nome}`); console.log(`CPF/CNPJ: ${cliente.cnpj_cpf}`); console.log(`E-mail: ${cliente.email}`); }

Resposta de sucesso (200)

json
{ "success": true, "message": "Registro encontrado", "data": { "id": 142, "nome": "Ana Carolina da Silva", "fantasia": null, "codigo":"CLI-0142", "tipo_pessoa": 1, "tipo_pessoa_label": "Pessoa Física", "consumidor_final": false, "cidade": "Sao Paulo", "uf": "SP", "cnpj_cpf": "123.456.789-00", "email": "ana.silva@email.com.br", "celular": "(11) 98765-4321", "tel_fixo": "(11) 3456-7890", "cep": "01310-100", "endereco": "Avenida Paulista", "numero":"1578", "complemento": "Sala 302", "bairro": "Bela Vista", "insc_estadual": null, "ie_isento": true, "limite_credito": "5000.00", "observacoes":"Cliente preferencial desde 2024" } }

Criar Cliente

POST /v1/clientes/

Cria um novo registro de cliente. Campos sensíveis (CPF/CNPJ, e-mail, telefone) são criptografados automaticamente antes de serem armazenados no banco de dados.

Escopo necessário: clientes: write

Campos do body

CampoTipoObrigatórioDescrição
nomestringSimNome completo ou razão social (máximo 255 caracteres)
fantasiastringNãoNome fantasia (máximo 255 caracteres)
codigostringNãoCódigo interno do cliente (máximo 50 caracteres)
tipo_pessoaintegerNão1 = Pessoa Física (padrão), 2 = Pessoa Jurídica
consumidor_finalbooleanNãoIndica se é consumidor final padrão (apenas 1 por empresa)
cnpj_cpfstringNãoCPF (ex: 123.456.789-00) ou CNPJ (ex: 12.345.678/0001-90)
emailstringNãoE-mail do cliente
celularstringNãoNúmero do celular (ex: (11) 98765-4321)
tel_fixostringNãoNúmero do telefone fixo (ex: (11) 3456-7890)
cepstringNãoCEP do endereço (ex: 01310-100)
ufstringNãoUnidade federativa (2 caracteres, ex: SP)
cidadestringNãoNome da cidade
bairrostringNãoNome do bairro
enderecostringNãoLogradouro
numerostringNãoNúmero do endereço
complementostringNãoComplemento do endereço
insc_estadualstringNãoInscrição estadual
ie_isentobooleanNãotrue se isento de inscrição estadual
limite_creditodecimalNãoLimite de crédito em R$ (ex: 5000.00)
observacoesstringNãoObservações gerais sobre o cliente

Tipo de pessoa

O campo tipo_pessoa define se o cliente é Pessoa Física ou Jurídica. Isso impacta a validação do campo cnpj_cpf:

tipo_pessoaValorDocumento esperadoFormato
1Pessoa FísicaCPF123.456.789-00
2Pessoa JurídicaCNPJ12.345.678/0001-90

Exemplo com cURL

bash
curl -X POST https://api-backend.bunto.com.br/v1/clientes/ \ -H 'Authorization: Bearer bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4' \ -H 'Content-Type: application/json' \ -d '{ "nome": "Fernanda Oliveira Santos", "tipo_pessoa": 1, "cnpj_cpf": "987.654.321-00", "email": "fernanda.santos@email.com.br", "celular": "(21) 99876-5432", "cep": "20040-020", "uf": "RJ", "cidade": "Rio de Janeiro", "bairro": "Centro", "endereco": "Rua da Assembleia", "numero":"10", "complemento": "Bloco B, Sala 501", "limite_credito": "3000.00", "observacoes":"Cliente indicado por parceiro comercial" }'

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", } # Criar cliente Pessoa Jurídica novo_cliente = { "nome": "Comercial Brasil Eireli", "fantasia": "Brasil Comercial", "tipo_pessoa": 2, "cnpj_cpf": "12.345.678/0001-90", "email": "contato@brasilcomercial.com.br", "celular": "(11) 91234-5678", "tel_fixo": "(11) 3210-9876", "cep": "04543-011", "uf": "SP", "cidade": "Sao Paulo", "bairro": "Itaim Bibi", "endereco": "Rua Funchal", "numero":"418", "complemento": "Andar 15", "insc_estadual": "123.456.789.012", "ie_isento": False, "limite_credito": "50000.00", "observacoes":"Conta corporativa - faturamento mensal", } resposta = requests.post(f"{BASE_URL}/clientes/", json=novo_cliente, headers=headers) dados = resposta.json() if dados["success"]: cliente_criado = dados["data"] print(f"Cliente criado com ID: {cliente_criado['id']}") print(f"Nome: {cliente_criado['nome']}") else: print(f"Erro ao criar cliente: {dados}")

Exemplo com JavaScript

javascript
const BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const novoCliente = { nome: "Comercial Brasil Eireli", fantasia: "Brasil Comercial", tipo_pessoa: 2, cnpj_cpf: "12.345.678/0001-90", email: "contato@brasilcomercial.com.br", celular: "(11) 91234-5678", tel_fixo: "(11) 3210-9876", cep: "04543-011", uf: "SP", cidade: "Sao Paulo", bairro: "Itaim Bibi", endereco: "Rua Funchal", numero: "418", complemento: "Andar 15", insc_estadual: "123.456.789.012", ie_isento: false, limite_credito: "50000.00", observacoes: "Conta corporativa - faturamento mensal", }; const resposta = await fetch(`${BASE_URL}/clientes/`, { method: "POST", headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify(novoCliente), }); const dados = await resposta.json(); if (dados.success) { console.log(`Cliente criado com ID: ${dados.data.id}`); console.log(`Nome: ${dados.data.nome}`); }

Resposta de sucesso (201)

json
{ "success": true, "message": "Registro criado com sucesso", "data": { "id": 203, "nome": "Comercial Brasil Eireli", "fantasia": "Brasil Comercial", "codigo":null, "tipo_pessoa": 2, "tipo_pessoa_label": "Pessoa Jurídica", "consumidor_final": false, "cidade": "Sao Paulo", "uf": "SP", "cnpj_cpf": "12.345.678/0001-90", "email": "contato@brasilcomercial.com.br", "celular": "(11) 91234-5678", "tel_fixo": "(11) 3210-9876", "cep": "04543-011", "endereco": "Rua Funchal", "numero":"418", "complemento": "Andar 15", "bairro": "Itaim Bibi", "insc_estadual": "123.456.789.012", "ie_isento": false, "limite_credito": "50000.00", "observacoes":"Conta corporativa - faturamento mensal" } }

Atualizar Cliente

Atualização completa

PUT /v1/clientes/{id}/

Atualiza todos os campos do cliente. Campos não enviados serão definidos como null (exceto campos obrigatórios).

Atualização parcial

PATCH /v1/clientes/{id}/

Atualiza apenas os campos enviados no body. Campos omitidos permanecem inalterados.

Escopo necessário: clientes: write

Exemplo com cURL (PATCH)

bash
curl -X PATCH https://api-backend.bunto.com.br/v1/clientes/142/ \ -H 'Authorization: Bearer bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4' \ -H 'Content-Type: application/json' \ -d '{ "email": "ana.carolina.novo@email.com.br", "celular": "(11) 91111-2222", "limite_credito": "8000.00" }'

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", } # Atualizar parcialmente (PATCH) - apenas os campos informados atualizacao = { "email": "ana.carolina.novo@email.com.br", "celular": "(11) 91111-2222", "limite_credito": "8000.00", } resposta = requests.patch(f"{BASE_URL}/clientes/142/", json=atualizacao, headers=headers) dados = resposta.json() if dados["success"]: cliente = dados["data"] print(f"Cliente {cliente['nome']} atualizado com sucesso") else: print(f"Erro: {dados}")

Exemplo com JavaScript

javascript
const BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const atualizacao = { email: "ana.carolina.novo@email.com.br", celular: "(11) 91111-2222", limite_credito: "8000.00", }; const resposta = await fetch(`${BASE_URL}/clientes/142/`, { method: "PATCH", headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify(atualizacao), }); const dados = await resposta.json(); if (dados.success) { console.log(`Cliente ${dados.data.nome} atualizado com sucesso`); }

Resposta de sucesso (200)

json
{ "success": true, "message": "Registro atualizado com sucesso", "data": { "id": 142, "nome": "Ana Carolina da Silva", "fantasia": null, "codigo":"CLI-0142", "tipo_pessoa": 1, "tipo_pessoa_label": "Pessoa Física", "consumidor_final": false, "cidade": "Sao Paulo", "uf": "SP", "cnpj_cpf": "123.456.789-00", "email": "ana.carolina.novo@email.com.br", "celular": "(11) 91111-2222", "tel_fixo": "(11) 3456-7890", "cep": "01310-100", "endereco": "Avenida Paulista", "numero":"1578", "complemento": "Sala 302", "bairro": "Bela Vista", "insc_estadual": null, "ie_isento": true, "limite_credito": "8000.00", "observacoes":"Cliente preferencial desde 2024" } }

Excluir Cliente

DELETE /v1/clientes/{id}/

Exclui permanentemente um cliente. A exclusão será recusada se o cliente possuir registros vinculados (pedidos de venda, propostas, contas financeiras, etc.).

Escopo necessário: clientes: delete

Exemplo com cURL

bash
curl -X DELETE https://api-backend.bunto.com.br/v1/clientes/203/ \ -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}"} resposta = requests.delete(f"{BASE_URL}/clientes/203/", headers=headers) dados = resposta.json() if dados["success"]: print("Cliente excluído com sucesso") else: print(f"Erro: {dados['message']}")

Exemplo com JavaScript

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

Resposta de sucesso (200)

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

Erros

Validação (400)

Retornado quando os dados enviados são inválidos.

json
{ "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Erro de validacao", "details": { "nome": ["Este campo é obrigatorio."], "cnpj_cpf": ["Ja existe um cliente com este CPF"] } } }

CPF/CNPJ duplicado (400)

json
{ "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Ja existe um cliente com este CNPJ", "details": { "cnpj_cpf": ["Ja existe um cliente com este CNPJ"] } } }

E-mail duplicado (400)

json
{ "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Ja existe um cliente com este email", "details": { "email": ["Ja existe um cliente com este email"] } } }

Consumidor final duplicado (400)

Apenas um cliente pode ser marcado como consumidor final por empresa.

json
{ "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Ja existe um consumidor final nesta empresa", "details": { "consumidor_final": ["Ja existe um consumidor final nesta empresa"] } } }

Não autenticado (401)

json
{ "detail": "Token invalido" }

Sem permissão (403)

Retornado quando o token não possui o escopo necessário.

json
{ "detail": "Token nao tem permissao para este recurso" }

Não encontrado (404)

Retornado quando o cliente não existe ou pertence a outra empresa.

json
{ "success": false, "error": { "code": "NOT_FOUND", "message": "Registro nao encontrado" } }

Cliente em uso (400)

Retornado ao tentar excluir um cliente que possui registros vinculados.

json
{ "success": false, "error": { "code": "PROTECTED_ERROR", "message": "Nao é possivel excluir o cliente pois está em uso", "details": { "registros_em_uso": [ "Pedido de Venda PV-001523", "Proposta PC-000042", "Conta a Receber CR-000891" ] } } }

Rate limit excedido (429)

json
{ "detail": "Limite de requisicoes excedido. Tente novamente em 45 segundos." }

Rate Limiting

Os limites de requisição são aplicados por token.

OperaçãoMétodosLimite
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. Implemente retry com backoff exponencial para lidar com esses casos.


Paginação

Endpoints de listagem retornam dados paginados.

ParâmetroTipoPadrãoMáximoDescrição
paginainteger1-Número da página
por_paginainteger25100Registros por página

Nota: Os parâmetros são pagina e por_pagina (em português), não page e per_page.

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

Exemplos Completos

Sincronizar clientes com sistema externo (Python)

python
import os import time import requests class BuntoClientes: """Cliente para o endpoint de clientes da API v1 do Bunto ERP.""" def __init__(self, token=None, base_url=None): self.token = token or os.environ["BUNTO_API_TOKEN"] self.base_url = base_url or "https://api-backend.bunto.com.br/v1" self.session = requests.Session() self.session.headers.update({ "Authorization": f"Bearer {self.token}", "Content-Type": "application/json", }) def _requisicao(self, metodo, endpoint, **kwargs): """Executa requisicao com retry para rate limit.""" url = f"{self.base_url}/{endpoint.lstrip('/')}" for tentativa in range(3): resposta = self.session.request(metodo, url, **kwargs) if resposta.status_code == 429: tempo = 2 ** tentativa * 15 print(f"Rate limit. Aguardando {tempo}s...") time.sleep(tempo) continue return resposta raise Exception("Limite de tentativas excedido") def listar(self, **filtros): """Lista clientes com filtros opcionais.""" resposta = self._requisicao("GET", "/clientes/", params=filtros) return resposta.json() def obter(self, cliente_id): """Obtém detalhes de um cliente (inclui dados sensíveis).""" resposta = self._requisicao("GET", f"/clientes/{cliente_id}/") return resposta.json() def criar(self, dados): """Cria um novo cliente.""" resposta = self._requisicao("POST", "/clientes/", json=dados) return resposta.json() def atualizar(self, cliente_id, dados): """Atualiza parcialmente um cliente.""" resposta = self._requisicao("PATCH", f"/clientes/{cliente_id}/", json=dados) return resposta.json() def excluir(self, cliente_id): """Exclui um cliente.""" resposta = self._requisicao("DELETE", f"/clientes/{cliente_id}/") return resposta.json() def listar_todos(self, **filtros): """Lista todos os clientes (com paginacao automatica).""" filtros["por_pagina"] = 100 filtros["pagina"] = 1 todos = [] while True: resultado = self.listar(**filtros) if not resultado["success"]: break todos.extend(resultado["data"]["resultados"]) paginacao = resultado["data"]["paginacao"] if paginacao["proxima"] is None: break filtros["pagina"] += 1 return todos # Uso api = BuntoClientes(ambiente="staging") # Listar todos os clientes PJ de Sao Paulo clientes_sp = api.listar_todos(tipo_pessoa=2, uf="SP") print(f"Total de PJs em SP: {len(clientes_sp)}") # Criar novo cliente resultado = api.criar({ "nome": "Padaria Bom Dia Ltda", "fantasia": "Padaria Bom Dia", "tipo_pessoa": 2, "cnpj_cpf": "98.765.432/0001-10", "email": "contato@padariabomdia.com.br", "celular": "(11) 95555-1234", "uf": "SP", "cidade": "Guarulhos", }) if resultado["success"]: novo_id = resultado["data"]["id"] print(f"Cliente criado: ID {novo_id}") # Obter detalhes completos detalhes = api.obter(novo_id) if detalhes["success"]: cliente = detalhes["data"] print(f"CNPJ: {cliente['cnpj_cpf']}") print(f"E-mail: {cliente['email']}")

Importar clientes de planilha (JavaScript/Node.js)

javascript
class BuntoClientes { constructor(token, baseUrl = null) { this.token = token ?? process.env.BUNTO_API_TOKEN; this.baseUrl = baseUrl ?? "https://api-backend.bunto.com.br/v1"; this.headers = { Authorization: `Bearer ${this.token}`, "Content-Type": "application/json", }; } async requisicao(metodo, endpoint, opcoes = {}) { const url = `${this.baseUrl}/${endpoint.replace(/^\//, "")}`; for (let tentativa = 0; tentativa < 3; tentativa++) { const resposta = await fetch(url, { method: metodo, headers: this.headers, ...opcoes, }); if (resposta.status === 429) { const tempo = 2 ** tentativa * 15 * 1000; console.log(`Rate limit. Aguardando ${tempo / 1000}s...`); await new Promise((resolve) => setTimeout(resolve, tempo)); continue; } return resposta.json(); } throw new Error("Limite de tentativas excedido"); } async criar(dados) { return this.requisicao("POST", "/clientes/", { body: JSON.stringify(dados), }); } async atualizar(clienteId, dados) { return this.requisicao("PATCH", `/clientes/${clienteId}/`, { body: JSON.stringify(dados), }); } } // Importar clientes de uma lista const api = new BuntoClientes(undefined, "staging"); const clientesParaImportar = [ { nome: "Roberto Mendes", tipo_pessoa: 1, cnpj_cpf: "111.222.333-44", email: "roberto.mendes@email.com.br", celular: "(31) 98888-7777", uf: "MG", cidade: "Belo Horizonte", }, { nome: "Tech Solutions SA", fantasia: "Tech Solutions", tipo_pessoa: 2, cnpj_cpf: "11.222.333/0001-44", email: "contato@techsolutions.com.br", tel_fixo: "(41) 3333-4444", uf: "PR", cidade: "Curitiba", }, ]; for (const cliente of clientesParaImportar) { const resultado = await api.criar(cliente); if (resultado.success) { console.log(`Criado: ${cliente.nome} (ID: ${resultado.data.id})`); } else { console.error(`Erro ao criar ${cliente.nome}:`, resultado); } // Respeitar rate limit de escrita (30/min) await new Promise((resolve) => setTimeout(resolve, 2100)); }

Códigos de Status HTTP

CódigoSignificadoQuando ocorre
200SucessoConsulta, atualização ou exclusão bem-sucedida
201CriadoCliente criado com sucesso via POST
400Erro de validaçãoDados inválidos, CPF/CNPJ duplicado, cliente em uso
401Não autenticadoToken ausente, inválido, expirado ou revogado
403Sem permissãoToken não tem escopo para clientes
404Não encontradoCliente não existe ou pertence a outra empresa
429Muitas requisiçõesRate limit excedido
500Erro internoErro inesperado no servidor
APIClientesCRUDcURLJavaScriptLGPDPythonREST
Recursos para IA