Formato de erro
Todos os erros retornam um objeto JSON no seguinte formato:{
"error": {
"type": "validation_error",
"message": "Campo 'name' é obrigatório.",
"code": "MISSING_REQUIRED_FIELD",
"details": [
{
"field": "name",
"message": "Campo obrigatório"
}
]
},
"meta": {
"request_id": "req_01jx8kz3m4n5p6q7r8s9t0u1v"
}
}
| Campo | Tipo | Descrição |
|---|---|---|
error.type | string | Categoria do erro (ex: validation_error) |
error.message | string | Mensagem legível para humanos |
error.code | string | Código de máquina para tratamento programático |
error.details | array? | Detalhes adicionais (ex: campos inválidos) |
meta.request_id | string | ID único da requisição para suporte |
Códigos HTTP
| Status | Tipo | Quando ocorre |
|---|---|---|
200 | Sucesso | Leitura bem-sucedida |
201 | Criado | Recurso criado com sucesso |
204 | Sem conteúdo | Exclusão bem-sucedida |
400 | validation_error | Corpo ou parâmetros inválidos |
401 | unauthorized | API Key ausente ou inválida |
403 | forbidden | Escopo insuficiente ou restrição de plano |
404 | not_found | Recurso não encontrado |
409 | conflict | Conflito de dados (ex: duplicata) |
422 | unprocessable_entity | Dados válidos mas impossíveis de processar |
429 | rate_limit_exceeded | Limite de requisições atingido |
500 | internal_error | Erro interno do servidor |
Referência de códigos de erro
Autenticação
| Código | Status | Descrição |
|---|---|---|
MISSING_API_KEY | 401 | Header Authorization ausente |
INVALID_API_KEY_FORMAT | 401 | Chave não começa com sk_live_ |
INVALID_API_KEY | 401 | Chave inválida, expirada ou revogada |
INSUFFICIENT_SCOPE | 403 | Escopo necessário não concedido à chave |
PLAN_RESTRICTION | 403 | Recurso não disponível no plano atual |
Validação
| Código | Status | Descrição |
|---|---|---|
INVALID_ID | 400 | ID de recurso com formato inválido |
MISSING_REQUIRED_FIELD | 400 | Campo obrigatório ausente |
INVALID_TYPE | 400 | Valor de enum inválido |
INVALID_PRIORITY | 400 | Prioridade inválida |
INVALID_CHANNEL | 400 | Canal não suportado |
CHANNEL_NOT_SUPPORTED | 400 | Canal não disponível na API pública |
MISSING_CONTENT | 400 | Conteúdo da mensagem ausente |
MISSING_MEDIA_URL | 400 | URL de mídia ausente para mensagens não-texto |
MISSING_TAG | 400 | Campo tag ausente |
Recursos
| Código | Status | Descrição |
|---|---|---|
NOT_FOUND | 404 | Recurso não encontrado na organização |
PIPELINE_NOT_FOUND | 404 | Funil de venda não encontrado |
STAGE_NOT_FOUND | 404 | Etapa não encontrada no funil de venda |
CONTACT_NOT_FOUND | 404 | Contato não encontrado |
DUPLICATE_CONTACT | 409 | Já existe contato com esse telefone/email |
DUPLICATE | 409 | Registro duplicado |
Processamento
| Código | Status | Descrição |
|---|---|---|
NO_WHATSAPP_JID | 422 | Contato sem WhatsApp configurado |
NO_WHATSAPP_INSTANCE | 422 | Nenhuma instância WhatsApp conectada |
NO_MESSENGER_PSID | 422 | Contato sem PSID do Messenger |
NO_MESSENGER_PAGE | 422 | Nenhuma página Messenger conectada |
NO_STAGES | 422 | Funil de venda sem etapas |
ALREADY_OPEN | 422 | Negócio já está aberto |
MESSENGER_SEND_ERROR | 500 | Erro ao enviar via Messenger API |
Rate Limiting
| Código | Status | Descrição |
|---|---|---|
RATE_LIMIT_EXCEEDED | 429 | Limite por minuto atingido |
RATE_LIMIT_BURST_EXCEEDED | 429 | Limite de burst (10s) atingido |
RATE_LIMIT_DAILY_EXCEEDED | 429 | Limite diário atingido |
WHATSAPP_INSTANCE_RATE_LIMIT | 429 | 30 msg/min por instância WhatsApp |
MESSENGER_PAGE_RATE_LIMIT | 429 | 30 msg/min por página Messenger |
Tratando erros em código
async function apiRequest(url, options = {}) {
const response = await fetch(`https://api.socialsell.ai/v1${url}`, {
...options,
headers: {
'Authorization': 'Bearer sk_live_...',
'Content-Type': 'application/json',
...options.headers
}
});
const data = await response.json();
if (!response.ok) {
const { error } = data;
switch (error.code) {
case 'RATE_LIMIT_EXCEEDED':
const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
// aguardar e tentar novamente
await new Promise(r => setTimeout(r, retryAfter * 1000));
return apiRequest(url, options);
case 'DUPLICATE_CONTACT':
// contato já existe — usar o ID retornado
return { existing: error.existing_contact };
default:
throw new Error(`[${error.code}] ${error.message}`);
}
}
return data;
}
import requests
import time
def api_request(path, method='GET', **kwargs):
url = f'https://api.socialsell.ai/v1{path}'
headers = {'Authorization': 'Bearer sk_live_...'}
response = requests.request(method, url, headers=headers, **kwargs)
data = response.json()
if not response.ok:
error = data.get('error', {})
code = error.get('code')
if code == 'RATE_LIMIT_EXCEEDED':
retry_after = int(response.headers.get('Retry-After', 60))
time.sleep(retry_after)
return api_request(path, method, **kwargs)
raise Exception(f"[{code}] {error.get('message')}")
return data
Header de Rate Limiting
Quando bem-sucedida, cada resposta inclui headers informativos:X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 2026-06-10T15:30:00.000Z
X-Request-Id: req_01jx8kz3m4n5p6q7r8s9t0u1v
Retry-After: 15

