MENU navbar-image

Introduction

API pública de integração do Br Envio: cadastrar e atualizar contatos (e tags) via Bearer API token.

O que esta API faz hoje

Este portal documenta o subset público para integradores (CRM, loja, ERP, legado).

Hoje as operações publicadas são:

Campanhas, disparo, modelos, setup de domínio, billing e Super Admin não entram aqui — usam o painel (JWT). Ver seção Fora deste portal.

Autenticação

Todas as rotas deste portal usam API token (não o login do painel).

  1. No painel: Conta → Tokens de API → criar token e copiar uma vez.
  2. Enviar o cabeçalho: Authorization: Bearer <seu_token>.
  3. Rate limit: 60 requisições/minuto por token.

Guia leigo: Tokens de API.

Base URL

Produção: https://api.brenvio.com.br

Exemplo completo: POST https://api.brenvio.com.br/api/v1/integration/contacts

Envelope JSON

Sucesso:

{ "success": true, "data": { }, "message": "..." }

Erro:

{ "success": false, "error": { "code": "CODIGO", "message": "texto legível" } }

Códigos comuns no upsert: UNAUTHORIZED, CONTACT_BLOCKLISTED, CONTACT_SUPPRESSED, UNKNOWN_FIELD_SLUG, RATE_LIMIT_EXCEEDED, VALIDATION_ERROR.

Idioma

Opcional: Accept-Language: pt-BR | en | es (mensagens de erro/sucesso).

Contatos (upsert)

Chave de identidade: e-mail (normalizado em minúsculas).

Campo Obrigatório Comportamento
email sim Cria se novo; atualiza se já existir
name não Nome de exibição
country_code + phone_number não Telefone nativo (DDI + dígitos). Default DDI 55 se vier telefone sem DDI
phone não Alternativa em uma string; o servidor normaliza
tags não Array de nomes; cria a tag se faltar
tag_match não append (default) = anexa sem remover; replace = o array enviado substitui o conjunto atual
fields não Objeto { "slug": valor } dos campos da base; upsert parcial (só os slugs enviados)

Higiene (não negociável):

Resposta inclui data.created (true = 201 criado, false = 200 atualizado).

Tags

Catálogo (CRUD)

Método Path Uso
GET /api/v1/integration/tags Listar (opcional ?search= e per_page)
POST /api/v1/integration/tags Criar { "name": "VIP" }
GET /api/v1/integration/tags/{id} Detalhe
PATCH/PUT /api/v1/integration/tags/{id} Renomear
DELETE /api/v1/integration/tags/{id} Excluir (remove vínculos; contatos ficam)

Vincular tags a contatos

No upsert de contatos:

  1. "tags": ["Lead CRM", "VIP"] — cria nomes que não existirem.
  2. tag_match omitido ou appendanexa (não apaga tags já no contato).
  3. tag_match: "replace" — o array vira o conjunto canônico (CRM manda a verdade).

Gerenciar tags na UI: ajuda — Tags.

Campos tipados

Os slugs de fields precisam existir em Conta → Campos da base no painel. Slug desconhecido → UNKNOWN_FIELD_SLUG.

Datas no valor: preferir AAAA-MM-DD.

Fora deste portal (painel)

Estas capacidades existem no produto, mas não têm endpoint público com API token no F1:

Capacidade Onde usar
Criar campanha / editor / modelos Painel → Campanhas / Modelos
Enviar teste e disparar campanha Painel → Testar e disparar
Métricas de envio Painel → Envios
Import/export CSV Painel → Contatos
Setup de domínio / DNS Painel → Setup de envio
CRUD completo de contatos (lista, delete) Painel (API token: upsert + tags)
Tokens (criar/revogar) Painel → Conta → Tokens de API

Quando o PO abrir PUBLISH de CRUD contatos/tags ou leitura de campanhas, este portal é regenerado (DOC 18).

Authenticating requests

To authenticate requests, include an Authorization header with the value "Bearer {YOUR_API_TOKEN}".

All authenticated endpoints are marked with a requires authentication badge in the documentation below.

Crie o token em Conta → Tokens de API no painel (https://painel.brenvio.com.br/settings/api-tokens). O valor em texto só aparece na criação.

Contact Integration

Upsert de contatos para CRM e sistemas externos. Autenticação: Authorization: Bearer <api_token> (token gerado em Conta → Tokens de API). Rate limit: 60 req/min por token. Envelope { success, data } / { success: false, error }.

Upsert contact

requires authentication

Cria ou atualiza um contato pelo e-mail. Tags são anexadas por nome (criadas se não existirem). Campos tipados (fields) são upsert parcial — só os slugs enviados. Não reativa contatos unsubscribed ou suppressed. Respeita blocklist do cliente e suppressão global.

Example request:
curl --request POST \
    "https://api.brenvio.com.br/api/v1/integration/contacts" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"email\": \"helena@crm.test\",
    \"name\": \"Helena\",
    \"country_code\": \"55\",
    \"phone_number\": \"11988887777\",
    \"phone\": \"+55 11 98888-7777\",
    \"tags\": [
        \"Lead CRM\",
        \"VIP\"
    ],
    \"tag_match\": \"append\",
    \"fields\": {
        \"empresa\": \"Acme\"
    }
}"
const url = new URL(
    "https://api.brenvio.com.br/api/v1/integration/contacts"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "email": "helena@crm.test",
    "name": "Helena",
    "country_code": "55",
    "phone_number": "11988887777",
    "phone": "+55 11 98888-7777",
    "tags": [
        "Lead CRM",
        "VIP"
    ],
    "tag_match": "append",
    "fields": {
        "empresa": "Acme"
    }
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.brenvio.com.br/api/v1/integration/contacts';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'email' => 'helena@crm.test',
            'name' => 'Helena',
            'country_code' => '55',
            'phone_number' => '11988887777',
            'phone' => '+55 11 98888-7777',
            'tags' => ['Lead CRM', 'VIP'],
            'tag_match' => 'append',
            'fields' => ['empresa' => 'Acme'],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, updated):


{
    "success": true,
    "message": "Contato atualizado via integração.",
    "data": {
        "id": 1,
        "email": "helena@crm.test",
        "created": false
    }
}
 

Example response (201, created):


{
    "success": true,
    "message": "Contato criado via integração.",
    "data": {
        "id": 1,
        "email": "helena@crm.test",
        "name": "Helena",
        "status": "active",
        "tags": [
            {
                "id": 1,
                "name": "VIP"
            }
        ],
        "fields": {
            "empresa": "Acme"
        },
        "created": true
    }
}
 

Example response (401, unauthorized):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Autenticação necessária."
    }
}
 

Example response (422, blocklisted):


{
    "success": false,
    "error": {
        "code": "CONTACT_BLOCKLISTED",
        "message": "Este e-mail ou domínio está na lista de bloqueio e não pode ser cadastrado."
    }
}
 

Example response (422, suppressed):


{
    "success": false,
    "error": {
        "code": "CONTACT_SUPPRESSED",
        "message": "Este e-mail ou domínio está na lista de supressão e não pode ser cadastrado."
    }
}
 

Example response (422, unknown_field):


{
    "success": false,
    "error": {
        "code": "UNKNOWN_FIELD_SLUG",
        "message": "Slug de campo desconhecido."
    }
}
 

Example response (429, rate_limited):


{
    "success": false,
    "error": {
        "code": "RATE_LIMIT_EXCEEDED",
        "message": "Limite de requisições excedido."
    }
}
 

Request      

POST api/v1/integration/contacts

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

email   string     

E-mail do contato (lowercase). Example: helena@crm.test

name   string  optional    

Nome de exibição. Example: Helena

country_code   string  optional    

DDI só dígitos (default 55 se vier phone). Example: 55

phone_number   string  optional    

Telefone só dígitos. Example: 11988887777

phone   string  optional    

Alternativa: telefone em uma string (normalizado no servidor). Example: +55 11 98888-7777

tags   string[]  optional    

Nomes de tags (cria se faltar). Com tag_match=append (default) anexa; com replace substitui o conjunto.

tag_match   string  optional    

append (default) ou replace. Example: append

fields   object  optional    

Valores de campos tipados por slug do catálogo.

Tags

Catálogo de marcadores (tags) da conta. Autenticação neste portal: Authorization: Bearer <api_token> nas rotas /api/v1/integration/tags*. Rate limit: 60 req/min por token. Envelope { success, data } / { success: false, error }.

List tags

requires authentication

Lista paginada de tags. Busca opcional por nome (search).

Example request:
curl --request GET \
    --get "https://api.brenvio.com.br/api/v1/integration/tags?search=vip&per_page=15" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.brenvio.com.br/api/v1/integration/tags"
);

const params = {
    "search": "vip",
    "per_page": "15",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.brenvio.com.br/api/v1/integration/tags';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'search' => 'vip',
            'per_page' => '15',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, ok):


{
    "success": true,
    "data": [
        {
            "id": 1,
            "name": "VIP"
        }
    ],
    "meta": {
        "current_page": 1,
        "per_page": 15,
        "total": 1,
        "last_page": 1
    }
}
 

Request      

GET api/v1/integration/tags

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

search   string  optional    

Filtro parcial no nome (case-insensitive). Example: vip

per_page   integer  optional    

Itens por página (1–100, default 15). Example: 15

Create tag

requires authentication

Cria uma tag pelo nome. Nome duplicado (case-insensitive) → validação 422.

Example request:
curl --request POST \
    "https://api.brenvio.com.br/api/v1/integration/tags" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Lead CRM\"
}"
const url = new URL(
    "https://api.brenvio.com.br/api/v1/integration/tags"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Lead CRM"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.brenvio.com.br/api/v1/integration/tags';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'name' => 'Lead CRM',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (201, created):


{
    "success": true,
    "message": "Tag criada.",
    "data": {
        "id": 1,
        "name": "Lead CRM"
    }
}
 

Request      

POST api/v1/integration/tags

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

name   string     

Nome do marcador. Example: Lead CRM

Get tag

requires authentication

Example request:
curl --request GET \
    --get "https://api.brenvio.com.br/api/v1/integration/tags/1" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.brenvio.com.br/api/v1/integration/tags/1"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.brenvio.com.br/api/v1/integration/tags/1';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, ok):


{
    "success": true,
    "data": {
        "id": 1,
        "name": "VIP"
    }
}
 

Example response (404, missing):


{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "…"
    }
}
 

Request      

GET api/v1/integration/tags/{tag}

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

tag   integer     

ID da tag. Example: 1

Update tag

requires authentication

Renomeia a tag. Não altera vínculos com contatos (só o nome).

Example request:
curl --request PUT \
    "https://api.brenvio.com.br/api/v1/integration/tags/1" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"VIP 2026\"
}"
const url = new URL(
    "https://api.brenvio.com.br/api/v1/integration/tags/1"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "VIP 2026"
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.brenvio.com.br/api/v1/integration/tags/1';
$response = $client->put(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'name' => 'VIP 2026',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, ok):


{
    "success": true,
    "message": "Tag atualizada.",
    "data": {
        "id": 1,
        "name": "VIP 2026"
    }
}
 

Request      

PUT api/v1/integration/tags/{tag}

PATCH api/v1/integration/tags/{tag}

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

tag   integer     

ID da tag. Example: 1

Body Parameters

name   string     

Novo nome. Example: VIP 2026

Delete tag

requires authentication

Remove a tag e os vínculos com contatos (cascade). Os contatos permanecem.

Example request:
curl --request DELETE \
    "https://api.brenvio.com.br/api/v1/integration/tags/1" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.brenvio.com.br/api/v1/integration/tags/1"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.brenvio.com.br/api/v1/integration/tags/1';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, ok):


{
    "success": true,
    "message": "Tag excluída.",
    "data": null
}
 

Request      

DELETE api/v1/integration/tags/{tag}

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

tag   integer     

ID da tag. Example: 1