Central de ajudaAdminQuem decide

API de Disparo Outbound: envie mensagens proativas pelo seu backend

Enfileire envios WhatsApp/Telegram com o mesmo worker da página Disparos. Auth, envio unitário/lote, templates Meta, opt-outs, limites e recibos.

A API de Disparo Outbound permite que o seu backend enfileire mensagens proativas nos canais conectados do workspace — a mesma fila, ritmo, lista de supressão e trilha de auditoria da página Disparos no console. Use a partir de CRMs, sistemas de pedido e agendadores quando precisar de envios disparados no servidor em escala.

URL base e autenticação

URL base
https://concierge.bentokit.ai/api/integrations/concierge/v1/dispatch
  • Authorization: Bearer czsk_… (chave do workspace em Acesso à API → Chaves)
  • Cada chamada fica no escopo do workspace da chave
  • Envios são assíncronos: valida e enfileira agora; um worker com ritmo entrega depois
  • Cabeçalho opcional Idempotency-Key (ou idempotencyKey no body) evita duplicar retentativas
Esqueleto cURL
curl -sS -X POST "https://concierge.bentokit.ai/api/integrations/concierge/v1/dispatch" \
  -H "Authorization: Bearer czsk_…" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-4958343-shipped" \
  -d '{ "channelId": "whatsapp-2", "to": "5521999999999", "text": "Olá!" }'

Gêmeo no console

  1. Criar uma chave de API

    Acesso à API → Chaves. Copie o segredo uma vez (czsk_…). Guarde só no servidor.

  2. Conectar um canal com envio proativo

    WhatsApp Cloud, WhatsApp Pessoal, Telegram, etc. O canal precisa aceitar envio proativo (a página Disparos mostra as rotas prontas).

  3. Ensaiar em Disparos (opcional)

    Monte um envio único no console primeiro. A API usa o mesmo worker e a mesma lista de supressão.

  4. Chamar a API pelo backend

    Prefira templates aprovados do provedor no WhatsApp Cloud oficial. Texto livre funciona nos canais que permitem.

Listar disparos recentes

GET / com status, batchId e limit opcionais (1–500, padrão 50) devolve as linhas recentes do workspace. Status: queued, sending, accepted, sent, delivered, read, failed, blocked, expired, cancelled.

Enviar uma mensagem

POST / devolve 202 com { dispatch } quando enfileirado, 409 quando bloqueado (ex.: opt-out), ou { dispatch, deduped: true } quando a chave de idempotência já existe. Exatamente um formato de conteúdo é obrigatório.

Body do POST (um dos três formatos)
{
  "channelId": "whatsapp-2",
  "to": "5521999999999",
  "ttlSeconds": 86400,
  "text": "…",
  "templateId": "tpl_…",
  "variables": { "name": "Ana" },
  "providerTemplate": {
    "name": "order_update",
    "language": "pt_BR",
    "parameters": ["Ana", "4958343"]
  },
  "idempotencyKey": "chave-estavel-opcional"
}
  • text: texto livre (canais que permitem free-form)
  • templateId + variables: mensagem salva do workspace com placeholders {{nome}}
  • providerTemplate: template aprovado estilo Meta (obrigatório no WhatsApp Cloud oficial)
  • ttlSeconds: 60–604800 (padrão 86400). Expirado na fila é descartado, nunca enviado atrasado
  • Omita channelId só se houver exatamente um canal de saída; senão envie o id ou receba channel_ambiguous

Envio em lote

POST /batch aceita os mesmos formatos com recipients: [{ to, variables? | parameters? }]. Até 500 destinatários por requisição. Idempotência de lote no tenant evita enfileirar duas vezes em retry.

Esboço POST /batch
{
  "channelId": "whatsapp-2",
  "providerTemplate": {
    "name": "order_update",
    "language": "pt_BR",
    "parameters": ["PLACEHOLDER"]
  },
  "recipients": [
    { "to": "5521999999999", "parameters": ["Ana", "4958343"] },
    { "to": "5521888888888", "parameters": ["Bruno", "4958344"] }
  ],
  "ttlSeconds": 86400
}

Destinatários a partir de leads

GET /recipients?channelId=…&q=…&limit=… projeta leads capturados como destinatários de telefone daquele canal (id normalizado, nome, telefone, e-mail, origem/status, optedOut). Só canais phone-kind; outros devolvem unsupportedKind: true até existir mapeamento de chat-id.

Mensagens salvas (templates do workspace)

  • GET|POST /templates — listar ou criar corpos com placeholders {{variavel}}
  • GET|PUT|DELETE /templates/:id — ler, atualizar, apagar
  • Só em canais que permitem free-form / mensagem salva

Templates do provedor (Meta)

  • GET /channels/:channelId/templates[?includeUnavailable=true] — aprovados por padrão, ou todos os status
  • POST /channels/:channelId/templates — enviar novo template se o canal declarar templateManagement
  • DELETE /channels/:channelId/templates/:name — apaga todas as línguas daquele nome (semântica do provedor)
Submeter template UTILITY da Meta
{
  "name": "order_update",
  "language": "pt_BR",
  "category": "UTILITY",
  "bodyText": "Olá {{1}}, seu pedido {{2}} está a caminho.",
  "bodyExamples": ["Ana", "4958343"],
  "footerText": "BentoKit"
}

Falhas de validação devolvem 400 com códigos estáveis (invalid_template_name, template_placeholders_not_sequential, template_examples_mismatch, …). Novos templates costumam ficar pending até a Meta revisar.

Lista de supressão (opt-outs)

  • GET /optouts — listar destinatários bloqueados
  • POST /optouts — { to, channelId? | channelKind? } bloqueia antes da fila
  • DELETE /optouts?to=…&channelKind=… — remover supressão
  • Honre a mesma lista nos seus sistemas para não recontatar quem saiu

Limites e erros

  • Texto do corpo ~4000 caracteres no máximo
  • Lote máximo 500 destinatários
  • Teto diário padrão 1000/workspace (env CONCIERGE_DISPATCH_DAILY_CAP) → 429 daily_dispatch_cap
  • Limite de rajada de enfileiramento (padrão 120/min) → 429 rate_limited
  • 4xx comuns: channel_not_found, no_dispatch_channel, channel_ambiguous, template_or_text_required, provider_template_not_approved, recipient_opted_out (blocked)
  • 402 plan_feature_missing quando outbound_campaigns não está no plano

Recibos de entrega de volta

Se o seu sistema precisa saber quando a mensagem foi aceita, entregue ou falhou, assine dispatch.* em Acesso à API → Webhooks (opcional). A maioria das integrações de CRM pode ignorar esses eventos e consultar GET /.

  • Chave de API só no servidor
  • WhatsApp oficial usa só providerTemplate aprovado
  • Idempotency-Key em todo envio de produção que possa retentar
  • Lista de supressão checada ou espelhada no CRM
  • TTL definido para não enviar promo atrasada se o canal ficar fora