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

API de Marketing

CRUD de conversões offline para Google e Meta Ads via API.

13/02/202613 min de leitura0 visualizações

Gerencie as conversões offline do Bunto ERP para integração com Google Ads e Meta Ads. Este endpoint permite listar, consultar, criar, atualizar e excluir registros de conversões offline (leads, oportunidades, vendas e pagamentos) via API.

Base URL

Produção:

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

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


Endpoints

Listar Conversões

GET /v1/marketing/

Escopo necessário: marketing: read

Retorna a lista paginada de conversões offline da empresa.

Query Parameters

ParâmetroTipoPadrãoDescrição
paginainteger1Número da página
por_paginainteger25Registros por página (máximo: 100)
buscastring-Busca por gclid ou fbclid
tipostring-Filtrar por tipo: lead, oportunidade, venda, pagamento
status_googlestring-Filtrar por status de envio ao Google (ex: enviado, pendente, erro)
data_iniciodate-Filtrar conversões a partir desta data (formato: YYYY-MM-DD)
data_fimdate-Filtrar conversões até esta data (formato: YYYY-MM-DD)
ordenarstringcriado_emCampo de ordenação: criado_em, valor_receita, tipo
direcaostringdescDireção da ordenação: asc ou desc

Exemplo com cURL

bash
curl 'https://api-backend.bunto.com.br/v1/marketing/?pagina=1&por_pagina=10&tipo=venda&data_inicio=2026-01-01&data_fim=2026-01-31&ordenar=valor_receita&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 conversões de venda do mês de janeiro resposta = requests.get( f"{BASE_URL}/marketing/", headers=headers, params={ "pagina": 1, "por_pagina": 25, "tipo": "venda", "data_inicio": "2026-01-01", "data_fim": "2026-01-31", "ordenar": "valor_receita", "direcao": "desc", }, ) dados = resposta.json() if dados["success"]: conversoes = dados["data"]["resultados"] paginacao = dados["data"]["paginacao"] print(f"Total de conversões: {paginacao['total_registros']}") for conv in conversoes: google = conv["status_google"] or "N/A" meta = conv["status_meta"] or "N/A" print(f" - [{conv['tipo']}] R$ {conv['valor_receita']} | Google: {google} | Meta: {meta}") 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", tipo: "venda", data_inicio: "2026-01-01", data_fim: "2026-01-31", ordenar: "valor_receita", direcao: "desc", }); const resposta = await fetch(`${BASE_URL}/marketing/?${params}`, { headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, }); const dados = await resposta.json(); if (dados.success) { const conversoes = dados.data.resultados; const paginacao = dados.data.paginacao; console.log(`Total de conversões: ${paginacao.total_registros}`); conversoes.forEach((conv) => { const google = conv.status_google || "N/A"; const meta = conv.status_meta || "N/A"; console.log(` - [${conv.tipo}] R$ ${conv.valor_receita} | Google: ${google} | Meta: ${meta}`); }); } else { console.error(`Erro: ${resposta.status}`); }

Resposta (200 OK)

json
{ "success": true, "message": "8 registros encontrados", "data": { "resultados": [ { "id": 120, "tipo": "venda", "valor_receita": "4500.00", "valor_lucro": "1350.00", "status_google": "enviado", "status_meta": "enviado", "criado_em": "2026-01-28T16:30:00-03:00" }, { "id": 118, "tipo": "venda", "valor_receita": "2800.00", "valor_lucro": "840.00", "status_google": "enviado", "status_meta": null, "criado_em": "2026-01-25T10:15:00-03:00" }, { "id": 115, "tipo": "venda", "valor_receita": "1200.00", "valor_lucro": "360.00", "status_google": "pendente", "status_meta": "pendente", "criado_em": "2026-01-20T09:00:00-03:00" } ], "paginacao": { "pagina_atual": 1, "total_paginas": 1, "total_registros": 8, "por_pagina": 25, "proxima": null, "anterior": null } } }

Campos da Listagem

CampoTipoDescrição
idintegerIdentificador único da conversão
tipostringTipo da conversão: lead, oportunidade, venda, pagamento
valor_receitadecimalValor da receita associada à conversão
valor_lucrodecimalValor do lucro associado à conversão
status_googlestring / nullStatus de envio ao Google Ads (ex: enviado, pendente, erro)
status_metastring / nullStatus de envio ao Meta Ads (ex: enviado, pendente, erro)
criado_emdatetimeData e hora de criação do registro

Obter Conversão

GET /v1/marketing/{id}/

Escopo necessário: marketing: read

Retorna os dados completos de uma conversão específica, incluindo parâmetros UTM, click IDs e datas de envio.

Exemplo com cURL

bash
curl https://api-backend.bunto.com.br/v1/marketing/120/ \ -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", } conversao_id = 120 resposta = requests.get(f"{BASE_URL}/marketing/{conversao_id}/", headers=headers) dados = resposta.json() if dados["success"]: conv = dados["data"] print(f"Conversão #{conv['id']} [{conv['tipo']}]") print(f"Receita: R$ {conv['valor_receita']}") print(f"Lucro: R$ {conv['valor_lucro']}") print(f"GCLID: {conv['gclid']}") print(f"FBCLID: {conv['fbclid']}") print(f"UTM: {conv['utm_source']} / {conv['utm_medium']} / {conv['utm_campaign']}") print(f"Google: {conv['status_google']} (enviado em {conv['google_enviado_em']})") print(f"Meta: {conv['status_meta']} (enviado em {conv['meta_enviado_em']})") else: print(f"Erro: {dados}")

Exemplo com JavaScript

javascript
const BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const conversaoId = 120; const resposta = await fetch(`${BASE_URL}/marketing/${conversaoId}/`, { headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, }); const dados = await resposta.json(); if (dados.success) { const conv = dados.data; console.log(`Conversão #${conv.id} [${conv.tipo}]`); console.log(`Receita: R$ ${conv.valor_receita}`); console.log(`Lucro: R$ ${conv.valor_lucro}`); console.log(`GCLID: ${conv.gclid}`); console.log(`FBCLID: ${conv.fbclid}`); console.log(`UTM: ${conv.utm_source} / ${conv.utm_medium} / ${conv.utm_campaign}`); console.log(`Google: ${conv.status_google} (enviado em ${conv.google_enviado_em})`); console.log(`Meta: ${conv.status_meta} (enviado em ${conv.meta_enviado_em})`); } else { console.error(`Erro: ${JSON.stringify(dados)}`); }

Resposta (200 OK)

json
{ "success": true, "message": "Registro encontrado", "data": { "id": 120, "tipo": "venda", "valor_receita": "4500.00", "valor_lucro": "1350.00", "status_google": "enviado", "status_meta": "enviado", "criado_em": "2026-01-28T16:30:00-03:00", "gclid": "CjwKCAiA-P-rBhBEEiwAQEXhH8Z2fG7kL9mN3pQ5rS7tU1vW3xY5zA", "fbclid": "IwAR1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4Y5z", "utm_source": "google", "utm_medium": "cpc", "utm_campaign": "campanha_verao_2026", "ocorrido_em": "2026-01-28T15:45:00-03:00", "google_enviado_em": "2026-01-28T16:35:00-03:00", "meta_enviado_em": "2026-01-28T16:35:00-03:00", "atualizado_em": "2026-01-28T16:35:00-03:00" } }

Campos do Detalhe (adicionais à listagem)

CampoTipoDescrição
gclidstring / nullGoogle Click ID (identificador de clique do Google Ads)
fbclidstring / nullFacebook Click ID (identificador de clique do Meta Ads)
utm_sourcestring / nullParâmetro UTM source (origem do tráfego)
utm_mediumstring / nullParâmetro UTM medium (meio do tráfego)
utm_campaignstring / nullParâmetro UTM campaign (nome da campanha)
ocorrido_emdatetime / nullData e hora em que a conversão efetivamente ocorreu
google_enviado_emdatetime / nullData e hora em que a conversão foi enviada ao Google Ads
meta_enviado_emdatetime / nullData e hora em que a conversão foi enviada ao Meta Ads
atualizado_emdatetime / nullData e hora da última atualização

Criar Conversão

POST /v1/marketing/

Escopo necessário: marketing: write

Cria uma nova conversão offline na empresa do token autenticado. Os parâmetros de click ID (gclid, fbclid) e UTM são opcionais, mas pelo menos um deles deve ser informado para que a conversão possa ser sincronizada com Google Ads ou Meta Ads.

Campos do Request Body

CampoTipoObrigatórioDescrição
tipostringSimTipo da conversão: lead, oportunidade, venda, pagamento
valor_receitadecimalNãoValor da receita (padrão: 0)
valor_lucrodecimalNãoValor do lucro
gclidstringNãoGoogle Click ID (máximo 255 caracteres)
fbclidstringNãoFacebook Click ID (máximo 255 caracteres)
utm_sourcestringNãoParâmetro UTM source (máximo 255 caracteres)
utm_mediumstringNãoParâmetro UTM medium (máximo 255 caracteres)
utm_campaignstringNãoParâmetro UTM campaign (máximo 255 caracteres)
ocorrido_emdatetimeNãoData e hora da conversão (formato ISO 8601; se não informado, usa a data atual)

Exemplo com cURL

bash
curl -X POST https://api-backend.bunto.com.br/v1/marketing/ \ -H 'Authorization: Bearer bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4' \ -H 'Content-Type: application/json' \ -d '{ "tipo": "venda", "valor_receita": 2500.00, "valor_lucro": 750.00, "gclid": "CjwKCAiA-P-rBhBEEiwAQEXhH_novoClickId123", "utm_source": "google", "utm_medium": "cpc", "utm_campaign": "campanha_carnaval_2026", "ocorrido_em": "2026-02-12T14:00:00-03: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", } nova_conversao = { "tipo": "venda", "valor_receita": 2500.00, "valor_lucro": 750.00, "gclid": "CjwKCAiA-P-rBhBEEiwAQEXhH_novoClickId123", "utm_source": "google", "utm_medium": "cpc", "utm_campaign": "campanha_carnaval_2026", "ocorrido_em": "2026-02-12T14:00:00-03:00", } resposta = requests.post(f"{BASE_URL}/marketing/", headers=headers, json=nova_conversao) dados = resposta.json() if dados["success"]: conv = dados["data"] print(f"Conversão criada com sucesso! ID: {conv['id']}") print(f"Tipo: {conv['tipo']}") print(f"Receita: R$ {conv['valor_receita']}") else: print(f"Erro ao criar conversão: {dados}")

Exemplo com JavaScript

javascript
const BASE_URL = "https://api-backend.bunto.com.br/v1"; const TOKEN = "bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4"; const novaConversao = { tipo: "venda", valor_receita: 2500.0, valor_lucro: 750.0, gclid: "CjwKCAiA-P-rBhBEEiwAQEXhH_novoClickId123", utm_source: "google", utm_medium: "cpc", utm_campaign: "campanha_carnaval_2026", ocorrido_em: "2026-02-12T14:00:00-03:00", }; const resposta = await fetch(`${BASE_URL}/marketing/`, { method: "POST", headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify(novaConversao), }); const dados = await resposta.json(); if (dados.success) { console.log(`Conversão criada com sucesso! ID: ${dados.data.id}`); console.log(`Tipo: ${dados.data.tipo}`); console.log(`Receita: R$ ${dados.data.valor_receita}`); } else { console.error(`Erro ao criar conversão:`, dados); }

Resposta (201 Created)

json
{ "success": true, "message": "Conversão criada com sucesso", "data": { "id": 125, "tipo": "venda", "valor_receita": "2500.00", "valor_lucro": "750.00", "status_google": null, "status_meta": null, "criado_em": "2026-02-12T15:30:00-03:00", "gclid": "CjwKCAiA-P-rBhBEEiwAQEXhH_novoClickId123", "fbclid": null, "utm_source": "google", "utm_medium": "cpc", "utm_campaign": "campanha_carnaval_2026", "ocorrido_em": "2026-02-12T14:00:00-03:00", "google_enviado_em": null, "meta_enviado_em": null, "atualizado_em": "2026-02-12T15:30:00-03:00" } }

Atualizar Conversão

PUT /v1/marketing/{id}/
PATCH /v1/marketing/{id}/

Escopo necessário: marketing: write

Atualiza uma conversã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/marketing/125/ \ -H 'Authorization: Bearer bnt_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4' \ -H 'Content-Type: application/json' \ -d '{ "valor_receita": 3200.00, "valor_lucro": 960.00, "fbclid": "IwAR1b2C3d4E5f6G7h8I9j0K_novoFbClickId456" }'

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", } conversao_id = 125 # Atualização parcial (PATCH) - corrigir valores e adicionar fbclid atualizacao = { "valor_receita": 3200.00, "valor_lucro": 960.00, "fbclid": "IwAR1b2C3d4E5f6G7h8I9j0K_novoFbClickId456", } resposta = requests.patch( f"{BASE_URL}/marketing/{conversao_id}/", headers=headers, json=atualizacao, ) dados = resposta.json() if dados["success"]: conv = dados["data"] print(f"Conversão atualizada! Receita: R$ {conv['valor_receita']}") print(f"FBCLID: {conv['fbclid']}") 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 conversaoId = 125; const atualizacao = { valor_receita: 3200.0, valor_lucro: 960.0, fbclid: "IwAR1b2C3d4E5f6G7h8I9j0K_novoFbClickId456", }; const resposta = await fetch(`${BASE_URL}/marketing/${conversaoId}/`, { method: "PATCH", headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify(atualizacao), }); const dados = await resposta.json(); if (dados.success) { console.log(`Conversão atualizada! Receita: R$ ${dados.data.valor_receita}`); console.log(`FBCLID: ${dados.data.fbclid}`); } else { console.error(`Erro ao atualizar:`, dados); }

Resposta (200 OK)

json
{ "success": true, "message": "Conversão atualizada com sucesso", "data": { "id": 125, "tipo": "venda", "valor_receita": "3200.00", "valor_lucro": "960.00", "status_google": null, "status_meta": null, "criado_em": "2026-02-12T15:30:00-03:00", "gclid": "CjwKCAiA-P-rBhBEEiwAQEXhH_novoClickId123", "fbclid": "IwAR1b2C3d4E5f6G7h8I9j0K_novoFbClickId456", "utm_source": "google", "utm_medium": "cpc", "utm_campaign": "campanha_carnaval_2026", "ocorrido_em": "2026-02-12T14:00:00-03:00", "google_enviado_em": null, "meta_enviado_em": null, "atualizado_em": "2026-02-12T16:45:00-03:00" } }

Excluir Conversão (Permanente)

DELETE /v1/marketing/{id}/

Escopo necessário: marketing: delete

Exclui permanentemente a conversão do banco de dados. Esta ação é irreversível -- diferente de outros endpoints, registros de marketing não utilizam soft delete.

Exemplo com cURL

bash
curl -X DELETE https://api-backend.bunto.com.br/v1/marketing/125/ \ -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}"} conversao_id = 125 resposta = requests.delete(f"{BASE_URL}/marketing/{conversao_id}/", headers=headers) dados = resposta.json() if dados["success"]: print("Conversão excluída permanentemente!") 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 conversaoId = 125; const resposta = await fetch(`${BASE_URL}/marketing/${conversaoId}/`, { method: "DELETE", headers: { Authorization: `Bearer ${TOKEN}`, }, }); const dados = await resposta.json(); if (dados.success) { console.log("Conversão excluída permanentemente!"); } else { console.error(`Erro ao excluir:`, dados); }

Resposta (200 OK)

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

Atenção: A exclusão de conversões de marketing é permanente. O registro é removido do banco de dados e não pode ser recuperado. Se a conversão já foi enviada ao Google Ads ou Meta Ads, a exclusão no Bunto não remove a conversão das plataformas de anúncios.


Erros Comuns

CódigoErroCausaSolução
400VALIDATION_ERRORDados enviados são inválidos (campo obrigatório ausente, tipo de conversão inválido, formato incorreto, etc.)Verifique os campos obrigatórios e os tipos de dados
401Token inválidoToken ausente, expirado, revogado ou mal formatadoVerifique se o header é Authorization: Bearer bnt_xxx
403Token não tem permissãoO token não possui o escopo marketing ou a ação necessária (read, write ou delete)Verifique os escopos do token no painel
404Não encontradoConversão não existe ou pertence a outra empresaConfirme o ID e se a conversão pertence à empresa do token
429Limite de requisições excedidoRate limit ultrapassado para o tipo de operaçãoImplemente retry com backoff exponencial

Exemplo de Resposta de Erro (400)

json
{ "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Erro de validação", "details": { "tipo": ["\"custom\" não é um valor válido. Valores aceitos: lead, oportunidade, venda, pagamento."] } } }

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çã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 requisições excedido. Tente novamente em 45 segundos." }

Boas práticas

  • Use por_pagina=100 para reduzir o número de requisições ao listar conversões
  • Implemente retry com backoff exponencial ao receber 429
  • Armazene dados em cache local quando possível
  • Use filtros de data (data_inicio e data_fim) e tipo para limitar o volume de dados retornados
  • Para atualizações em lote, use PATCH apenas com os campos alterados para economizar requisições de escrita
  • Envie o gclid ou fbclid no momento da criação para garantir a atribuição correta da conversão

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}"} todas_as_conversoes = [] url = f"{BASE_URL}/marketing/?por_pagina=100" while url: resposta = requests.get(url, headers=headers) dados = resposta.json() if not dados["success"]: break todas_as_conversoes.extend(dados["data"]["resultados"]) url = dados["data"]["paginacao"]["proxima"] print(f"Total obtido: {len(todas_as_conversoes)} conversões")
APICRUDcURLJavaScriptMarketingPythonREST
Recursos para IA