API de Logística
CRUD de formas de envio e configurações logísticas via API.
Gerencie as formas de envio do Bunto ERP. Este endpoint permite listar, consultar, criar, atualizar e excluir formas de envio (transportadoras, Correios, Jadlog, etc.) via API.
Base URL
Produção:
https://api-backend.bunto.com.br/v1/logistica/
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: logistica com a ação correspondente (read, write ou delete).
Endpoints
Listar Formas de Envio
GET /v1/logistica/
Escopo necessário: logistica: read
Retorna a lista paginada de formas de envio da empresa.
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 |
tipo_logistica | string | - | Filtrar por tipo: transportadora, correios, jadlog, total_express, gateway_logistico, customizado, loggi |
ativo | boolean | - | Filtrar por status: true (ativas) ou false (inativas) |
ordenar | string | descricao | Campo de ordenação: descricao, tipo_logistica, criado_em |
direcao | string | asc | Direção da ordenação: asc ou desc |
Exemplo com cURL
bashcurl 'https://api-backend.bunto.com.br/v1/logistica/?pagina=1&por_pagina=10&tipo_logistica=correios&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 formas de envio do tipo Correios resposta = requests.get( f"{BASE_URL}/logistica/", headers=headers, params={ "pagina": 1, "por_pagina": 25, "tipo_logistica": "correios", "ordenar": "descricao", "direcao": "asc", }, ) dados = resposta.json() if dados["success"]: formas = dados["data"]["resultados"] paginacao = dados["data"]["paginacao"] print(f"Total de formas de envio: {paginacao['total_registros']}") for forma in formas: print(f" - [{forma['tipo_logistica']}] {forma['descricao']}") 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_logistica: "correios", ordenar: "descricao", direcao: "asc", }); const resposta = await fetch(`${BASE_URL}/logistica/?${params}`, { headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, }); const dados = await resposta.json(); if (dados.success) { const formas = dados.data.resultados; const paginacao = dados.data.paginacao; console.log(`Total de formas de envio: ${paginacao.total_registros}`); formas.forEach((forma) => { console.log(` - [${forma.tipo_logistica}] ${forma.descricao}`); }); } else { console.error(`Erro: ${resposta.status}`); }
Resposta (200 OK)
json{ "success": true, "message": "5 registros encontrados", "data": { "resultados": [ { "id": 1, "tipo_logistica": "correios", "descricao": "Correios - PAC", "url_rastreamento": "https://www.linkcorreios.com.br/?id=", "ativo": true, "criado_em": "2026-01-15T10:00:00-03:00" }, { "id": 2, "tipo_logistica": "correios", "descricao": "Correios - SEDEX", "url_rastreamento": "https://www.linkcorreios.com.br/?id=", "ativo": true, "criado_em": "2026-01-15T10:05:00-03:00" }, { "id": 3, "tipo_logistica": "jadlog", "descricao": "Jadlog - .Package", "url_rastreamento": "https://www.jadlog.com.br/jadlog/tracking?cte=", "ativo": true, "criado_em": "2026-01-20T14:30:00-03:00" } ], "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 forma de envio |
tipo_logistica | string | Tipo da logística (transportadora, correios, jadlog, total_express, gateway_logistico, customizado, loggi) |
descricao | string | Descrição da forma de envio |
url_rastreamento | string / null | URL base para rastreamento de encomendas |
ativo | boolean | Se a forma de envio está ativa |
criado_em | datetime | Data e hora de criação |
Obter Forma de Envio
GET /v1/logistica/{id}/
Escopo necessário: logistica: read
Retorna os dados completos de uma forma de envio específica, incluindo campos adicionais de detalhe.
Exemplo com cURL
bashcurl https://api-backend.bunto.com.br/v1/logistica/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", } forma_envio_id = 1 resposta = requests.get(f"{BASE_URL}/logistica/{forma_envio_id}/", headers=headers) dados = resposta.json() if dados["success"]: forma = dados["data"] print(f"Forma de envio: {forma['descricao']}") print(f"Tipo: {forma['tipo_logistica']}") print(f"URL rastreamento: {forma['url_rastreamento']}") else: print(f"Erro: {dados}")
Exemplo com JavaScript
javascriptconst BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const formaEnvioId = 1; const resposta = await fetch(`${BASE_URL}/logistica/${formaEnvioId}/`, { headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, }); const dados = await resposta.json(); if (dados.success) { const forma = dados.data; console.log(`Forma de envio: ${forma.descricao}`); console.log(`Tipo: ${forma.tipo_logistica}`); console.log(`URL rastreamento: ${forma.url_rastreamento}`); } else { console.error(`Erro: ${JSON.stringify(dados)}`); }
Resposta (200 OK)
json{ "success": true, "message": "Registro encontrado", "data": { "id": 1, "tipo_logistica": "correios", "descricao": "Correios - PAC", "url_rastreamento": "https://www.linkcorreios.com.br/?id=", "ativo": true, "criado_em": "2026-01-15T10:00:00-03:00", "modelo_etiqueta_id": null, "atualizado_em": "2026-02-05T14:30:00-03:00" } }
Campos do Detalhe (adicionais à listagem)
| Campo | Tipo | Descrição |
|---|---|---|
modelo_etiqueta_id | integer / null | ID do modelo de etiqueta vinculado |
atualizado_em | datetime | Data e hora da última atualização |
Criar Forma de Envio
POST /v1/logistica/
Escopo necessário: logistica: write
Cria uma nova forma de envio na empresa do token autenticado.
Campos do Request Body
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
tipo_logistica | string | Sim | Tipo da logística: transportadora, correios, jadlog, total_express, gateway_logistico, customizado, loggi (máximo 20 caracteres) |
descricao | string | Sim | Descrição da forma de envio (máximo 200 caracteres) |
url_rastreamento | string | Não | URL base para rastreamento de encomendas |
ativo | boolean | Não | Se a forma de envio está ativa (padrão: true) |
Exemplo com cURL
bashcurl -X POST https://api-backend.bunto.com.br/v1/logistica/ \ -H 'Authorization: Bearer bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4' \ -H 'Content-Type: application/json' \ -d '{ "tipo_logistica": "correios", "descricao": "Correios - SEDEX 10", "url_rastreamento": "https://www.linkcorreios.com.br/?id=", "ativo": true }'
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_forma = { "tipo_logistica": "correios", "descricao": "Correios - SEDEX 10", "url_rastreamento": "https://www.linkcorreios.com.br/?id=", "ativo": True, } resposta = requests.post(f"{BASE_URL}/logistica/", headers=headers, json=nova_forma) dados = resposta.json() if dados["success"]: forma = dados["data"] print(f"Forma de envio criada com sucesso! ID: {forma['id']}") print(f"Descrição: {forma['descricao']}") else: print(f"Erro ao criar forma de envio: {dados}")
Exemplo com JavaScript
javascriptconst BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const novaForma = { tipo_logistica: "correios", descricao: "Correios - SEDEX 10", url_rastreamento: "https://www.linkcorreios.com.br/?id=", ativo: true, }; const resposta = await fetch(`${BASE_URL}/logistica/`, { method: "POST", headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify(novaForma), }); const dados = await resposta.json(); if (dados.success) { console.log(`Forma de envio criada com sucesso! ID: ${dados.data.id}`); console.log(`Descrição: ${dados.data.descricao}`); } else { console.error(`Erro ao criar forma de envio:`, dados); }
Resposta (201 Created)
json{ "success": true, "message": "Forma de envio criada com sucesso", "data": { "id": 8, "tipo_logistica": "correios", "descricao": "Correios - SEDEX 10", "url_rastreamento": "https://www.linkcorreios.com.br/?id=", "ativo": true, "criado_em": "2026-02-12T15:30:00-03:00", "modelo_etiqueta_id": null, "atualizado_em": "2026-02-12T15:30:00-03:00" } }
Atualizar Forma de Envio
PUT /v1/logistica/{id}/
PATCH /v1/logistica/{id}/
Escopo necessário: logistica: write
Atualiza uma forma de envio 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/logistica/8/ \ -H 'Authorization: Bearer bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4' \ -H 'Content-Type: application/json' \ -d '{ "descricao": "Correios - SEDEX 10 (Capitais)", "ativo": true }'
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", } forma_envio_id = 8 # Atualização parcial (PATCH) - apenas os campos que mudaram atualizacao = { "descricao": "Correios - SEDEX 10 (Capitais)", "ativo": True, } resposta = requests.patch( f"{BASE_URL}/logistica/{forma_envio_id}/", headers=headers, json=atualizacao, ) dados = resposta.json() if dados["success"]: forma = dados["data"] print(f"Forma de envio atualizada! Descrição: {forma['descricao']}") 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 formaEnvioId = 8; const atualizacao = { descricao: "Correios - SEDEX 10 (Capitais)", ativo: true, }; const resposta = await fetch(`${BASE_URL}/logistica/${formaEnvioId}/`, { method: "PATCH", headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify(atualizacao), }); const dados = await resposta.json(); if (dados.success) { console.log(`Forma de envio atualizada! Descrição: ${dados.data.descricao}`); } else { console.error(`Erro ao atualizar:`, dados); }
Resposta (200 OK)
json{ "success": true, "message": "Forma de envio atualizada com sucesso", "data": { "id": 8, "tipo_logistica": "correios", "descricao": "Correios - SEDEX 10 (Capitais)", "url_rastreamento": "https://www.linkcorreios.com.br/?id=", "ativo": true, "criado_em": "2026-02-12T15:30:00-03:00", "modelo_etiqueta_id": null, "atualizado_em": "2026-02-12T16:45:00-03:00" } }
Excluir Forma de Envio (Soft Delete)
DELETE /v1/logistica/{id}/
Escopo necessário: logistica: delete
Desativa a forma de envio (soft delete). O registro não é removido permanentemente do banco de dados -- o campo ativo é definido como false, preservando o histórico e os vínculos com expedições.
Exemplo com cURL
bashcurl -X DELETE https://api-backend.bunto.com.br/v1/logistica/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}"} forma_envio_id = 8 resposta = requests.delete(f"{BASE_URL}/logistica/{forma_envio_id}/", headers=headers) dados = resposta.json() if dados["success"]: print("Forma de envio 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 formaEnvioId = 8; const resposta = await fetch(`${BASE_URL}/logistica/${formaEnvioId}/`, { method: "DELETE", headers: { Authorization: `Bearer ${TOKEN}`, }, }); const dados = await resposta.json(); if (dados.success) { console.log("Forma de envio excluída com sucesso!"); } else { console.error(`Erro ao excluir:`, dados); }
Resposta (200 OK)
json{ "success": true, "message": "Registro excluído com sucesso" }
Importante: Formas de envio desativadas via soft delete não aparecem mais nas listagens com filtro ativo=true. Para visualizar formas de envio inativas, filtre por ativo=false.
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 inválido | Token ausente, expirado, revogado ou mal formatado | Verifique se o header é Authorization: Bearer bnt_xxx |
| 403 | Token não tem permissão | O token não possui o escopo logistica ou a ação necessária (read, write ou delete) | Verifique os escopos do token no painel |
| 404 | Não encontrado | Forma de envio não existe ou pertence a outra empresa | Confirme o ID e se a forma de envio pertence à empresa do token |
| 429 | Limite de requisições 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 validação", "details": { "tipo_logistica": ["Este campo é obrigatório."], "descricao": ["Certifique-se de que este campo não tenha mais de 200 caracteres."] } } }
Exemplo de Resposta de Erro (403)
json{ "detail": "Token não tem permissão 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 requisições excedido. Tente novamente em 45 segundos." }
Boas práticas
- Use
por_pagina=100para reduzir o número de requisições ao listar formas de envio - 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_formas = [] url = f"{BASE_URL}/logistica/?por_pagina=100" while url: resposta = requests.get(url, headers=headers) dados = resposta.json() if not dados["success"]: break todas_as_formas.extend(dados["data"]["resultados"]) url = dados["data"]["paginacao"]["proxima"] print(f"Total obtido: {len(todas_as_formas)} formas de envio")