Documentação API WhatsApp e SDR

API WhatsApp e SDR — SDRBOT.ai

API REST para envio de mensagens WhatsApp Business, templates Meta, RCS, gestão de leads, formulários públicos de captação e webhooks assinados. SDR com IA — qualifique prospects e automatize conversas via API com exemplos em cURL, PHP, Python e Node.js.

Autenticação

A autenticação usa uma API Key no formato sk_live_..., gerada no painel do SDRBOT.ai. Envie a chave no header Authorization como Bearer token ou, alternativamente, no header X-API-Key. Os formulários públicos (seção Captação) são a única exceção — dispensam autenticação.

Base URL

https://sdrbot.ai/api/v1

Header de Autenticação

Authorization: Bearer sk_live_xxxxxxxxxxxxx

Ou, de forma equivalente:

X-API-Key: sk_live_xxxxxxxxxxxxx

Codigos de Erro

Codigo HTTP Descrição
200 Sucesso
201 Recurso criado com sucesso
204 Sucesso sem corpo na resposta (exclusao)
400 Requisicao inválida (parâmetros faltando ou incorretos)
401 Nao autorizado (token invalido ou ausente)
403 Proibido (sem permissao para o recurso)
404 Recurso nao encontrado
409 Conflito (recurso duplicado)
422 Entidade nao processavel (validacao falhou)
429 Rate limit excedido
500 Erro interno do servidor

Formato de Erro

{
  "error": {
    "code": "validation_error",
    "message": "The given data was invalid.",
    "details": {
      "campo": ["Mensagem de validacao"]
    }
  }
}

O campo code identifica o erro de forma estavel (ex: validation_error, lead_exists, missing_template_variables, rate_limit_exceeded) — use-o para tratamento programatico em vez da mensagem.

Rate Limits

Limite Valor
Requisicoes por minuto 60
Requisicoes por dia 10.000

Cada resposta inclui os headers X-RateLimit-Limit e X-RateLimit-Remaining para acompanhamento do consumo. Quando o rate limit e excedido, a API retorna 429 Too Many Requests com o header Retry-After indicando quantos segundos aguardar.

Leads

GET /api/v1/leads Listar leads

Retorna a lista paginada de leads.

Parâmetros de Query

Parâmetro Tipo Descrição
page int Numero da pagina (default: 1)
per_page int Itens por pagina (default: 25, max: 100)
phone string Filtrar por telefone
email string Filtrar por email
temperature string Filtrar por temperatura: hot, warm, cool, cold, frozen
sort string Campo de ordenacao; prefixe com - para ordem decrescente (ex: -created_at)

Exemplos

curl -X GET "https://sdrbot.ai/api/v1/leads?page=1&per_page=25&temperature=hot" \
  -H "Authorization: Bearer SEU_TOKEN_AQUI" \
  -H "Accept: application/json"
import requests

url = "https://sdrbot.ai/api/v1/leads"
headers = {
    "Authorization": "Bearer SEU_TOKEN_AQUI",
    "Accept": "application/json"
}
params = {
    "page": 1,
    "per_page": 25,
    "temperature": "hot"
}

response = requests.get(url, headers=headers, params=params)
data = response.json()
print(data)
const response = await fetch('https://sdrbot.ai/api/v1/leads?page=1&per_page=25&temperature=hot', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer SEU_TOKEN_AQUI',
    'Accept': 'application/json'
  }
});

const data = await response.json();
console.log(data);
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://sdrbot.ai/api/v1/leads?page=1&per_page=25&temperature=hot');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer SEU_TOKEN_AQUI',
    'Accept: application/json'
]);

$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);
print_r($data);
?>
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer SEU_TOKEN_AQUI");
client.DefaultRequestHeaders.Add("Accept", "application/json");

var response = await client.GetAsync("https://sdrbot.ai/api/v1/leads?page=1&per_page=25&temperature=hot");
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
Resposta 200 OK
{
  "data": [
    {
      "id": 1234,
      "name": "Joao Silva",
      "email": "joao@empresa.com",
      "phone": "5551999999999",
      "company_name": "Empresa LTDA",
      "temperature": "hot",
      "lead_score": 85,
      "created_at": "2026-01-10T14:30:00Z",
      "updated_at": "2026-01-15T09:20:00Z"
    }
  ],
  "meta": {
    "current_page": 1,
    "per_page": 25,
    "total": 150,
    "total_pages": 6
  }
}
POST /api/v1/leads Criar lead

Parâmetros (Body JSON)

Parâmetro Tipo Obrigatório Descrição
phone string Sim Telefone com DDD e código do pais (ex: 5551999999999) — normalizado automaticamente
name string Nao Nome do contato
email string Nao Email do contato
company_name string Nao Nome da empresa
deal_value number Nao Valor estimado do negocio

Exemplos

curl -X POST "https://sdrbot.ai/api/v1/leads" \
  -H "Authorization: Bearer SEU_TOKEN_AQUI" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "phone": "5551888888888",
    "name": "Maria Santos",
    "email": "maria@empresa.com",
    "company_name": "Tech Solutions",
    "deal_value": 15000
  }'
import requests

url = "https://sdrbot.ai/api/v1/leads"
headers = {
    "Authorization": "Bearer SEU_TOKEN_AQUI",
    "Content-Type": "application/json",
    "Accept": "application/json"
}
payload = {
    "phone": "5551888888888",
    "name": "Maria Santos",
    "email": "maria@empresa.com",
    "company_name": "Tech Solutions",
    "deal_value": 15000
}

response = requests.post(url, json=payload, headers=headers)
print(response.json())
const response = await fetch('https://sdrbot.ai/api/v1/leads', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer SEU_TOKEN_AQUI',
    'Content-Type': 'application/json',
    'Accept': 'application/json'
  },
  body: JSON.stringify({
    phone: '5551888888888',
    name: 'Maria Santos',
    email: 'maria@empresa.com',
    company_name: 'Tech Solutions',
    deal_value: 15000
  })
});

const data = await response.json();
console.log(data);
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://sdrbot.ai/api/v1/leads');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer SEU_TOKEN_AQUI',
    'Content-Type: application/json',
    'Accept: application/json'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'phone' => '5551888888888',
    'name' => 'Maria Santos',
    'email' => 'maria@empresa.com',
    'company_name' => 'Tech Solutions',
    'deal_value' => 15000
]));

$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);
print_r($data);
?>
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer SEU_TOKEN_AQUI");
client.DefaultRequestHeaders.Add("Accept", "application/json");

var payload = new {
    phone = "5551888888888",
    name = "Maria Santos",
    email = "maria@empresa.com",
    company_name = "Tech Solutions",
    deal_value = 15000
};

var json = System.Text.Json.JsonSerializer.Serialize(payload);
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://sdrbot.ai/api/v1/leads", content);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
Resposta 201 Created
{
  "id": 1235,
  "phone": "5551888888888",
  "name": "Maria Santos",
  "email": "maria@empresa.com",
  "company_name": "Tech Solutions",
  "deal_value": 15000
}
Erro 409 Conflict — telefone ja cadastrado
{
  "error": {
    "code": "validation_error",
    "message": "The given data was invalid.",
    "details": {
      "phone": ["Resource already exists"]
    }
  }
}

Cada telefone e unico por conta. Para atualizar um lead existente, use o PUT /api/v1/leads/{id}.

GET /api/v1/leads/{id} Buscar lead por ID

Retorna os dados de um lead especifico pelo seu ID.

Exemplos

curl -X GET "https://sdrbot.ai/api/v1/leads/1234" \
  -H "Authorization: Bearer SEU_TOKEN_AQUI" \
  -H "Accept: application/json"
import requests

url = "https://sdrbot.ai/api/v1/leads/1234"
headers = {
    "Authorization": "Bearer SEU_TOKEN_AQUI",
    "Accept": "application/json"
}

response = requests.get(url, headers=headers)
data = response.json()
print(data)
const response = await fetch('https://sdrbot.ai/api/v1/leads/1234', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer SEU_TOKEN_AQUI',
    'Accept': 'application/json'
  }
});

const data = await response.json();
console.log(data);
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://sdrbot.ai/api/v1/leads/1234');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer SEU_TOKEN_AQUI',
    'Accept: application/json'
]);

$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);
print_r($data);
?>
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer SEU_TOKEN_AQUI");
client.DefaultRequestHeaders.Add("Accept", "application/json");

var response = await client.GetAsync("https://sdrbot.ai/api/v1/leads/1234");
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
Resposta 200 OK
{
  "data": {
    "id": 1234,
    "name": "Joao Silva",
    "email": "joao@empresa.com",
    "phone": "5551999999999",
    "company_name": "Empresa LTDA",
    "temperature": "hot",
    "lead_score": 85,
    "created_at": "2026-01-10T14:30:00Z",
    "updated_at": "2026-01-15T09:20:00Z"
  }
}
PUT /api/v1/leads/{id} Atualizar lead

Parâmetros (Body JSON)

Aceita os mesmos campos do POST (phone, name, email, company_name, deal_value), todos opcionais. Apenas os campos enviados serao atualizados.

Exemplos

curl -X PUT "https://sdrbot.ai/api/v1/leads/1234" \
  -H "Authorization: Bearer SEU_TOKEN_AQUI" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "company_name": "Empresa LTDA",
    "deal_value": 50000
  }'
import requests

url = "https://sdrbot.ai/api/v1/leads/1234"
headers = {
    "Authorization": "Bearer SEU_TOKEN_AQUI",
    "Content-Type": "application/json",
    "Accept": "application/json"
}
payload = {
    "company_name": "Empresa LTDA",
    "deal_value": 50000
}

response = requests.put(url, json=payload, headers=headers)
print(response.json())
const response = await fetch('https://sdrbot.ai/api/v1/leads/1234', {
  method: 'PUT',
  headers: {
    'Authorization': 'Bearer SEU_TOKEN_AQUI',
    'Content-Type': 'application/json',
    'Accept': 'application/json'
  },
  body: JSON.stringify({
    company_name: 'Empresa LTDA',
    deal_value: 50000
  })
});

const data = await response.json();
console.log(data);
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://sdrbot.ai/api/v1/leads/1234');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer SEU_TOKEN_AQUI',
    'Content-Type: application/json',
    'Accept: application/json'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'company_name' => 'Empresa LTDA',
    'deal_value' => 50000
]));

$response = curl_exec($ch);
curl_close($ch);
print_r(json_decode($response, true));
?>
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer SEU_TOKEN_AQUI");
client.DefaultRequestHeaders.Add("Accept", "application/json");

var payload = new {
    company_name = "Empresa LTDA",
    deal_value = 50000
};

var json = System.Text.Json.JsonSerializer.Serialize(payload);
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PutAsync("https://sdrbot.ai/api/v1/leads/1234", content);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
Resposta 200 OK
{
  "data": {
    "id": 1234,
    "name": "Joao Silva",
    "email": "joao@empresa.com",
    "phone": "5551999999999",
    "company_name": "Empresa LTDA",
    "temperature": "hot",
    "lead_score": 85,
    "deal_value": 50000,
    "created_at": "2026-01-10T14:30:00Z",
    "updated_at": "2026-08-11T10:15:00Z"
  }
}
DELETE /api/v1/leads/{id} Excluir lead

Exemplos

curl -X DELETE "https://sdrbot.ai/api/v1/leads/1234" \
  -H "Authorization: Bearer SEU_TOKEN_AQUI" \
  -H "Accept: application/json"
import requests

url = "https://sdrbot.ai/api/v1/leads/1234"
headers = {
    "Authorization": "Bearer SEU_TOKEN_AQUI",
    "Accept": "application/json"
}

response = requests.delete(url, headers=headers)
print(response.status_code)  # 204
const response = await fetch('https://sdrbot.ai/api/v1/leads/1234', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer SEU_TOKEN_AQUI',
    'Accept': 'application/json'
  }
});

console.log(response.status);  // 204
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://sdrbot.ai/api/v1/leads/1234');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer SEU_TOKEN_AQUI',
    'Accept: application/json'
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $httpCode;  // 204
?>
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer SEU_TOKEN_AQUI");
client.DefaultRequestHeaders.Add("Accept", "application/json");

var response = await client.DeleteAsync("https://sdrbot.ai/api/v1/leads/1234");
Console.WriteLine(response.StatusCode);  // NoContent (204)
Resposta 204 No Content

Retorna status 204 sem corpo na resposta.

Mensagens WhatsApp

POST /api/v1/whatsapp/messages Enviar mensagem WhatsApp

Envia mensagens via WhatsApp Business API. Suporta texto livre, templates pre-aprovados pela Meta e midia (imagem, video, documento e audio). Importante: fora da janela de 24 horas de atendimento, a Meta exige template aprovado — texto livre e midia só chegam em conversas ativas.

Parâmetros Comuns (Body JSON)

Parâmetro Tipo Obrigatório Descrição
integration_id int Sim ID do canal (integração) WhatsApp que fara o envio
type string Sim Tipo: text, template, image, video, document, audio
phone / lead_id / whatsapp_user_id string / int / string Um deles Destinatario: telefone com código do pais (ex: 5551999999999), ID do lead ou ID do usuario WhatsApp

Parâmetros por Tipo

Tipo Parâmetros
text text (obrigatório) — conteudo da mensagem
template template_id ou template_name (obrigatório); template_language (opcional, default do template ou pt_BR); variables — objeto nomeado ou array posicional na ordem das variaveis
image / video / document / audio media_url ou media_id (obrigatório); caption (opcional); filename (obrigatório para document)

Exemplos

curl -X POST "https://sdrbot.ai/api/v1/whatsapp/messages" \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "integration_id": 1,
    "phone": "5551999999999",
    "type": "text",
    "text": "Ola Joao! Tudo bem? Gostaria de agendar uma demonstracao do nosso produto."
  }'
import requests

url = "https://sdrbot.ai/api/v1/whatsapp/messages"
headers = {
    "Authorization": "Bearer sk_live_xxxxxxxxxxxxx",
    "Content-Type": "application/json"
}
payload = {
    "integration_id": 1,
    "phone": "5551999999999",
    "type": "text",
    "text": "Ola Joao! Tudo bem? Gostaria de agendar uma demonstracao do nosso produto."
}

response = requests.post(url, json=payload, headers=headers)
print(response.json())
const response = await fetch('https://sdrbot.ai/api/v1/whatsapp/messages', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sk_live_xxxxxxxxxxxxx',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    integration_id: 1,
    phone: '5551999999999',
    type: 'text',
    text: 'Ola Joao! Tudo bem? Gostaria de agendar uma demonstracao do nosso produto.'
  })
});

const data = await response.json();
console.log(data);
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://sdrbot.ai/api/v1/whatsapp/messages');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer sk_live_xxxxxxxxxxxxx',
    'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'integration_id' => 1,
    'phone' => '5551999999999',
    'type' => 'text',
    'text' => 'Ola Joao! Tudo bem? Gostaria de agendar uma demonstracao do nosso produto.'
]));

$response = curl_exec($ch);
curl_close($ch);
print_r(json_decode($response, true));
?>
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer sk_live_xxxxxxxxxxxxx");

var payload = new {
    integration_id = 1,
    phone = "5551999999999",
    type = "text",
    text = "Ola Joao! Tudo bem? Gostaria de agendar uma demonstracao do nosso produto."
};

var json = System.Text.Json.JsonSerializer.Serialize(payload);
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://sdrbot.ai/api/v1/whatsapp/messages", content);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);

Exemplo: Mensagem com Template

Templates precisam de aprovacao previa da Meta. O campo variables aceita objeto nomeado (recomendado) ou array posicional na ordem das variaveis do template. Se faltar variavel obrigatoria, a API retorna o erro missing_template_variables listando os campos ausentes.

curl -X POST "https://sdrbot.ai/api/v1/whatsapp/messages" \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "integration_id": 1,
    "lead_id": 1234,
    "type": "template",
    "template_id": 42,
    "variables": { "nome": "Joao", "empresa": "Empresa LTDA" }
  }'

Exemplo: Mensagem com Imagem

curl -X POST "https://sdrbot.ai/api/v1/whatsapp/messages" \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "integration_id": 1,
    "phone": "5551999999999",
    "type": "image",
    "media_url": "https://seusite.com.br/img/proposta-comercial.png",
    "caption": "Confira nossa proposta comercial personalizada!"
  }'

Exemplo: Documento

curl -X POST "https://sdrbot.ai/api/v1/whatsapp/messages" \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "integration_id": 1,
    "lead_id": 1234,
    "type": "document",
    "media_url": "https://seusite.com.br/docs/proposta.pdf",
    "filename": "proposta-comercial.pdf"
  }'
Resposta 200 OK
{
  "id": "msg_abc123def456",
  "status": "sent",
  "timestamp": "2026-08-11T10:30:00Z"
}

Templates

GET /api/v1/whatsapp/templates Listar templates WhatsApp

Lista os templates HSM da integração, com variaveis, preview e status de aprovacao na Meta. Use o id retornado como template_id no envio.

Parâmetros de Query

Parâmetro Tipo Descrição
integration_id int Obrigatório — ID do canal WhatsApp
category string Filtrar por categoria
context string Filtrar por contexto
meta_approved_only boolean Somente templates aprovados pela Meta (true/false)

Exemplo

curl -X GET "https://sdrbot.ai/api/v1/whatsapp/templates?integration_id=1&meta_approved_only=true" \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxx" \
  -H "Accept: application/json"
Resposta 200 OK
{
  "data": [
    {
      "id": 42,
      "integration_id": 1,
      "name": "Boas Vindas",
      "meta_template_name": "boas_vindas",
      "description": "Mensagem de abertura para novos leads",
      "category": "Warming",
      "variables": ["nome", "empresa"],
      "preview": "Ola Joao, bem-vindo! Vi que a Empresa LTDA conheceu nosso produto...",
      "language": "pt_BR",
      "status": "approved",
      "stats": {
        "usage_count": 128,
        "success_rate": "98.40"
      }
    }
  ]
}

Mensagens RCS

POST /api/v1/rcs/messages Enviar mensagem RCS

Envia mensagens via RCS (Rich Communication Services). Suporta texto, arquivo, cards ricos, carousels, texto com sugestoes de resposta e localizacao.

Parâmetros Comuns (Body JSON)

Parâmetro Tipo Obrigatório Descrição
type string Sim Tipo: text, file, card, carousel, replyable_text, location
phone / lead_id string / int Um deles Destinatario: telefone com código do pais ou ID do lead

Exemplo: Texto Simples

Ate 4.096 caracteres.

curl -X POST "https://sdrbot.ai/api/v1/rcs/messages" \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "5551999999999",
    "type": "text",
    "text": "Ola! Obrigado pelo seu interesse. Como posso ajudar?"
  }'

Exemplo: Arquivo

Imagem, video ou documento via URL publica, com o mime_type correspondente.

curl -X POST "https://sdrbot.ai/api/v1/rcs/messages" \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "lead_id": 1234,
    "type": "file",
    "file_url": "https://seusite.com.br/docs/catalogo.pdf",
    "mime_type": "application/pdf"
  }'

Exemplo: Card

Titulo de ate 200 caracteres e ate 4 botoes de acao (url, call, reply).

curl -X POST "https://sdrbot.ai/api/v1/rcs/messages" \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "5551999999999",
    "type": "card",
    "title": "Plano Empresarial",
    "description": "Ideal para empresas com mais de 50 colaboradores. Inclui suporte prioritario e integração completa.",
    "media_url": "https://seusite.com.br/img/plano-empresarial.jpg",
    "buttons": [
      {
        "type": "url",
        "text": "Ver detalhes",
        "url": "https://seusite.com.br/planos/empresarial"
      },
      {
        "type": "reply",
        "text": "Quero contratar",
        "payload": "contratar_empresarial"
      }
    ]
  }'

Exemplo: Carousel

De 2 a 10 cards; card_width aceita SMALL ou MEDIUM (default).

curl -X POST "https://sdrbot.ai/api/v1/rcs/messages" \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "5551999999999",
    "type": "carousel",
    "card_width": "MEDIUM",
    "cards": [
      {
        "title": "Plano Starter",
        "description": "Para pequenas empresas. Ate 10 usuarios.",
        "media_url": "https://seusite.com.br/img/plano-starter.jpg",
        "buttons": [
          { "type": "reply", "text": "Saber mais", "payload": "info_starter" }
        ]
      },
      {
        "title": "Plano Business",
        "description": "Para empresas em crescimento. Ate 50 usuarios.",
        "media_url": "https://seusite.com.br/img/plano-business.jpg",
        "buttons": [
          { "type": "reply", "text": "Saber mais", "payload": "info_business" }
        ]
      }
    ]
  }'

Exemplo: Texto com Opcoes de Resposta

Ate 11 sugestoes de resposta rapida, cada uma com text e payload.

curl -X POST "https://sdrbot.ai/api/v1/rcs/messages" \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "5551999999999",
    "type": "replyable_text",
    "text": "Qual horario funciona melhor para uma demonstracao?",
    "quick_replies": [
      { "text": "Manha (9h-12h)", "payload": "horario_manha" },
      { "text": "Tarde (14h-17h)", "payload": "horario_tarde" },
      { "text": "Noite (18h-20h)", "payload": "horario_noite" }
    ]
  }'

Exemplo: Localizacao

curl -X POST "https://sdrbot.ai/api/v1/rcs/messages" \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "lead_id": 1234,
    "type": "location",
    "latitude": -30.0346,
    "longitude": -51.2177,
    "label": "IAGENTE - Escritorio Porto Alegre"
  }'
Resposta 200 OK
{
  "id": "rcs_xyz789abc123",
  "status": "sent",
  "timestamp": "2026-08-11T11:00:00Z"
}

Formulários Públicos

Capture leads de formularios do seu site direto na pipeline, sem backend e sem expor sua API Key: a autenticação e feita por um token opaco (frm_...) na propria URL, gerado no painel ao criar o formulario. Cada formulario tem configuracao propria de dominios permitidos (CORS), honeypot, rate limit por IP e assinatura HMAC opcional.

POST /api/forms/{form_key} Criar/atualizar lead via formulario

Aceita application/json, application/x-www-form-urlencoded e multipart/form-data — funciona com um <form> HTML puro ou via fetch.

Campos

Campo Obrigatório Descrição
phone Sim Telefone do lead — normalizado automaticamente
name, email, company_name, role Nao Dados do contato
utm_source, utm_medium, utm_campaign, utm_term, utm_content Nao Parâmetros de atribuicao de campanha
Campos mapeados Nao Campos personalizados configurados no formulario (painel)

Exemplo

curl -X POST "https://sdrbot.ai/api/forms/frm_SEU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Maria Santos",
    "phone": "5551999999999",
    "email": "maria@empresa.com",
    "utm_source": "google",
    "utm_medium": "cpc",
    "utm_campaign": "institucional"
  }'
Resposta 200 OK
{
  "success": true,
  "lead_id": 123,
  "submission_id": 456,
  "duplicate": false
}

Se o telefone ja existir na conta, o lead e atualizado e duplicate retorna true. Envios que caem no honeypot tambem retornam 200 (silenciosamente descartados).

Codigos de Status

Codigo Erro Significado
200 Lead criado/atualizado (inclusive honeypot silencioso)
401 invalid_signature Assinatura HMAC nao confere
403 origin_not_allowed Dominio fora da lista de origens permitidas
404 form_not_found Token invalido ou formulario pausado
422 validation_error Campo obrigatório phone ausente
429 rate_limit_exceeded Limite por IP ou por conta atingido

Assinatura HMAC opcional

Se o formulario tiver um webhook_secret configurado, envie o header X-Signature com o HMAC-SHA256 do corpo bruto:

SECRET="seu_secret"
BODY='{"phone":"5551999999999"}'
SIG=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')

curl -X POST "https://sdrbot.ai/api/forms/frm_SEU_TOKEN" \
  -H "X-Signature: sha256=$SIG" \
  -H "Content-Type: application/json" \
  -d "$BODY"
GET /api/forms/{form_key}/ping Health check do formulario

Valida o token sem criar lead — retorna 200 se o formulario esta ativo. Util para monitorar a integração.

Webhooks

POST /api/v1/webhooks Criar webhook

Parâmetros (Body JSON)

Parâmetro Tipo Obrigatório Descrição
name string Sim Nome de identificacao do webhook
url string Sim URL de callback (HTTPS)
events array Sim Lista de eventos para escutar (ver tabela abaixo)
curl -X POST "https://sdrbot.ai/api/v1/webhooks" \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CRM Interno",
    "url": "https://seusite.com.br/webhooks/sdrbot",
    "events": ["lead.created", "lead.qualified", "message.received"]
  }'
Resposta 201 Created
{
  "id": 5,
  "name": "CRM Interno",
  "url": "https://seusite.com.br/webhooks/sdrbot",
  "events": ["lead.created", "lead.qualified", "message.received"],
  "signing_secret": "whsec_a1b2c3d4e5f6..."
}

Guarde o signing_secret com segurança — ele e usado para validar a assinatura das entregas (ver Verificacao de Assinatura).

GET /api/v1/webhooks Listar webhooks
curl -X GET "https://sdrbot.ai/api/v1/webhooks" \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxx" \
  -H "Accept: application/json"
POST /api/v1/webhooks/{id}/test Testar webhook

Envia um evento de teste para a URL configurada — valide a entrega e a assinatura antes de ir para produção.

curl -X POST "https://sdrbot.ai/api/v1/webhooks/5/test" \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxx" \
  -H "Accept: application/json"

Eventos Disponiveis

Evento Descrição
lead.created Novo lead criado
lead.updated Lead atualizado
lead.qualified Lead qualificado pela IA
message.received Mensagem recebida do lead
message.sent Mensagem enviada ao lead
handoff.created Atendimento transferido para humano
handoff.closed Atendimento humano encerrado

Formato do Webhook

POST https://seusite.com.br/webhooks/sdrbot

Headers:
  Content-Type: application/json
  X-Webhook-Signature: sha256=abc123def456...

Body:
{
  "id": "evt_789xyz",
  "event": "lead.qualified",
  "timestamp": "2026-08-11T10:30:00Z",
  "data": {
    "lead_id": 1234,
    "phone": "5551999999999",
    "name": "Joao Silva",
    "email": "joao@empresa.com",
    "company_name": "Empresa LTDA"
  }
}

Verificacao de Assinatura

Cada entrega inclui o header X-Webhook-Signature no formato sha256=<hex> — o HMAC-SHA256 do corpo bruto da requisição, calculado com o signing_secret retornado na criacao do webhook. Sempre valide antes de processar, usando comparacao de tempo constante.

<?php
$secret = 'whsec_seu_signing_secret';
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';

$expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    echo json_encode(['error' => 'Assinatura invalida']);
    exit;
}

// Assinatura válida - processar o webhook
$evento = json_decode($payload, true);

switch ($evento['event']) {
    case 'lead.created':
        // Processar novo lead
        break;
    case 'lead.qualified':
        // Processar lead qualificado
        break;
    case 'message.received':
        // Processar mensagem recebida
        break;
}

http_response_code(200);
echo json_encode(['ok' => true]);
?>
import hmac
import hashlib
import json
from flask import Flask, request, jsonify

app = Flask(__name__)
SECRET = 'whsec_seu_signing_secret'

@app.route('/webhooks/sdrbot', methods=['POST'])
def handle_webhook():
    payload = request.get_data()
    signature = request.headers.get('X-Webhook-Signature', '')

    expected = 'sha256=' + hmac.new(
        SECRET.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(expected, signature):
        return jsonify({'error': 'Assinatura invalida'}), 401

    evento = json.loads(payload)

    if evento['event'] == 'lead.created':
        # Processar novo lead
        pass
    elif evento['event'] == 'lead.qualified':
        # Processar lead qualificado
        pass
    elif evento['event'] == 'message.received':
        # Processar mensagem recebida
        pass

    return jsonify({'ok': True}), 200
const crypto = require('crypto');
const express = require('express');
const app = express();

const SECRET = 'whsec_seu_signing_secret';

app.post('/webhooks/sdrbot', express.raw({ type: 'application/json' }), (req, res) => {
    const payload = req.body;
    const signature = req.headers['x-webhook-signature'] || '';

    const expected = 'sha256=' + crypto
        .createHmac('sha256', SECRET)
        .update(payload)
        .digest('hex');

    if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
        return res.status(401).json({ error: 'Assinatura invalida' });
    }

    const evento = JSON.parse(payload);

    switch (evento.event) {
        case 'lead.created':
            // Processar novo lead
            break;
        case 'lead.qualified':
            // Processar lead qualificado
            break;
        case 'message.received':
            // Processar mensagem recebida
            break;
    }

    res.json({ ok: true });
});
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("webhooks/sdrbot")]
public class SdrbotWebhookController : ControllerBase
{
    private const string Secret = "whsec_seu_signing_secret";

    [HttpPost]
    public IActionResult HandleWebhook()
    {
        using var reader = new StreamReader(Request.Body);
        var payload = reader.ReadToEndAsync().Result;
        var signature = Request.Headers["X-Webhook-Signature"].ToString();

        using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(Secret));
        var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload));
        var expected = "sha256=" + BitConverter.ToString(hash).Replace("-", "").ToLower();

        if (!CryptographicOperations.FixedTimeEquals(
            Encoding.UTF8.GetBytes(expected),
            Encoding.UTF8.GetBytes(signature)))
        {
            return Unauthorized(new { error = "Assinatura invalida" });
        }

        var evento = JsonDocument.Parse(payload).RootElement;
        var eventType = evento.GetProperty("event").GetString();

        switch (eventType)
        {
            case "lead.created":
                // Processar novo lead
                break;
            case "lead.qualified":
                // Processar lead qualificado
                break;
            case "message.received":
                // Processar mensagem recebida
                break;
        }

        return Ok(new { ok = true });
    }
}

Precisa de ajuda? Entre em contato com nosso suporte tecnico pelo WhatsApp ou acesse a Central de Ajuda.