Mensageria
Envie mensagens do bot para usuários, canais e times. As respostas em thread são limitadas a 10 por mensagem pai, com um único nível de aninhamento. É possível editar uma mensagem em até 72h reenviando o mesmo `bot_message_id`.
Nesta página
Enviar uma mensagem do bot
Envia uma mensagem para usuários, canais ou times. Anexe até 25 botões interativos por mensagem — links, URLs de callback assinadas, modais, formulários internos, comandos, prompts de IA, workflows e auto-respostas. O mesmo endpoint atende respostas em thread (até 10 respostas por mensagem-pai, um nível de profundidade), impersonação do bot via `platform_settings` (nome/avatar/ephemeral no Slack) e edição de mensagens — reenviar com o mesmo `bot_message_id` em até 72 horas edita a mensagem original.
Corpo da requisição
Destinatários
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| target_users | array<string> | Opcional | UUIDs de usuário, e-mails ou IDs externos. É necessário pelo menos um de target_users / target_channels / target_teams. |
| target_channels | array<string | object> | Opcional | IDs de canal como strings, ou objetos { id, channel_type?, thread? }. Use thread (timestamp/id pai) para responder em uma thread existente. |
| target_teams | array<string> | Opcional | UUIDs de time. Todos os membros do time recebem a mensagem. |
| skip_users_on_time_off | boolean | Opcional | Quando true, usuários marcados como OOO / de folga são ignorados. |
Conteúdo
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| message | string | Opcional | Texto simples ou um subconjunto HTML seguro. Obrigatório se messages não for enviado. |
| messages | array | Opcional | Payloads específicos por plataforma (avançado). Obrigatório se message for omitido. |
| image_url | string (https) | Opcional | URL HTTPS de imagem para anexar à mensagem. |
| metadata | object | Opcional | Metadata personalizada livre anexada à mensagem e ecoada nos corpos de callback. |
Threads e edição
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| bot_message_id | string | Opcional | ID de idempotência personalizado. Reenvie o mesmo valor em até 72 horas para editar a mensagem original. |
| thread_responses | array<{ message: string }> | Opcional | Até 10 respostas publicadas sob o mesmo pai em uma única chamada. Apenas um nível de aninhamento. |
Identidade e impersonação
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| send_as_user | string (UUID) | Opcional | Só Slack. Só admin. Publica com o nome e avatar de outro membro. Mutuamente exclusivo com platform_settings.bot_username, bot_icon_url e bot_icon_emoji. |
Botões
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| buttons | array<Button> | Opcional | Até 25 botões interativos ou de link. Contrato completo campo a campo: Objeto Button ↓. O servidor gera button_id como $btn/<uuid4> (ids do cliente são sobrescritos). |
Configurações de plataforma
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| platform_settings | object | Opcional | Overrides de identidade/ephemeral só Slack: { bot_username?, bot_icon_url? | bot_icon_emoji?, is_ephemeral? }. Outras plataformas ignoram o bloco. Mutuamente exclusivo com send_as_user. |
Objeto Button (`buttons[]`)
Contrato completo de cada entrada em buttons (máx. 25 por mensagem). Os cinco callbacks (callback_url, callback_form, callback_command, callback_prompt, callback_workflow) são mutuamente exclusivos. modal_body combina com callback_url OU callback_workflow. response combina com tudo. Veja também a seção Interactive buttons da página para a matriz, verificação de assinatura e receitas.
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| label | string (≤ 40) | Obrigatório | Texto exibido no botão. |
| label_after_click | string (≤ 40) | Opcional | Substitui label após o clique (ou após enviar o modal). Padrão: igual a label. |
| button_type | "link" | "interactive" | Obrigatório | link abre url no navegador. interactive dispara uma das capacidades de callback abaixo. |
| url | string (https) | Opcional | Obrigatório quando button_type = "link". URL que o usuário abre. |
| value | string (≤ 2000) | Opcional | Obrigatório quando button_type = "interactive". Ecoado nos POSTs de callback. Também como {{trigger.button_value}} em workflows. |
| callback_url | string (https, ≤ 2048) | Opcional | POST assinado de saída no clique e no envio do modal. Mutuamente exclusivo com os outros quatro callbacks. Ver prosa Interactive buttons para verificação HMAC. |
| modal_body | object | Opcional | Abre um modal no clique. Combina com callback_url OU callback_workflow. Modais com inputs exigem um desses (input_without_callback). Contrato completo: objeto modal_body ↓ e blocks ↓. |
| callback_form | string (form UUID) | Opcional | Abre um formulário interno do Dailybot. Apenas UUID (liste via /v1/forms/). Mutuamente exclusivo. Desconhecido/arquivado → 400 button_callback_form_not_found. |
| callback_command | string (≤ 200) | Opcional | Executa um comando conhecido do Dailybot como o clicker (ex. help). O prefixo legado "prompt: …" é rejeitado — use callback_prompt. Mutuamente exclusivo. |
| callback_prompt | string (≤ 2000) | Opcional | Prompt de IA em texto livre executado como o usuário que clica (sua cota/permissões). Vazio ou longo demais → 400 button_callback_prompt_invalid. Mutuamente exclusivo. |
| callback_workflow | string (workflow UUID) | Opcional | Dispara um workflow ativo api_trigger na org do chamador. Apenas UUID. Desconhecido/inativo/outra org → 400 button_callback_workflow_not_found. Mutuamente exclusivo. |
| response | object | Opcional | Auto-resposta ao clicker: { message (≤2000, obrigatório), buttons? (recursivo), replace_original?, ephemeral? }. Combina com qualquer forma de botão. Contrato completo: objeto response ↓. |
| callback_auth | object | Opcional | Auth de transporte estática para o POST de saída — só válida com callback_url. Aditiva à assinatura HMAC. Credenciais somente escrita. Contrato completo: objeto callback_auth ↓. |
| destroy_button | boolean | Opcional | Padrão true. Se false, o botão permanece clicável; cada clique é um dispatch novo com um X-Dailybot-Delivery novo. |
| button_id | string ($btn/<uuid4>) | Opcional | Gerado pelo servidor. Ecoado em cada callback. Valores do cliente são sobrescritos — não envie este campo. |
| platform_settings | object | Opcional | Overrides raros por plataforma (legado). Prefira os campos top-level do botão. |
| payload | object | Opcional | Payload opaco livre. Os novos campos interativos devem ficar no top-level do botão, não dentro de payload. |
Objeto modal_body
Anexado a um Button interactive para abrir um modal leve. Tamanho serializado ≤ 8 KiB. Os blocos estão detalhados em [modal_body.blocks[] ↓](#send-message-modal-block).
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| title | string (≤ 200) | Obrigatório | Título do modal. |
| submit_label | string (≤ 200) | Opcional | Rótulo do botão de envio. Padrão: "Submit". |
| blocks | array (1..10) | Obrigatório | Exatamente os tipos text, input e divider (1–10). modal_body serializado ≤ 8 KiB. Slack renderiza nativamente; outras plataformas coletam conversacionalmente. Campos do bloco: [modal_body.blocks[] ↓](#send-message-modal-block). |
Item de modal_body.blocks[]
1–10 blocos dentro de modal_body.blocks. Apenas text, input e divider são permitidos.
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| type | "text" | "input" | "divider" | Obrigatório | Tipo de bloco. Apenas esses três valores são aceitos. |
| text | string (≤ 3000) | Opcional | Obrigatório para type: "text". Texto somente de exibição. |
| name | string | Opcional | Obrigatório para type: "input". Deve coincidir com ^[a-z][a-z0-9_]{0,62}$ e ser único no modal. Os valores chegam como modal_fields.<name> / {{trigger.fields.<name>}}. |
| label | string (≤ 200) | Opcional | Obrigatório para type: "input". Rótulo do campo mostrado ao usuário. |
| multiline | boolean | Opcional | Somente input. Padrão false. |
| required | boolean | Opcional | Somente input. Padrão false. |
| placeholder | string (≤ 200) | Opcional | Somente input. Placeholder opcional. |
| max_length | integer (1..3000) | Opcional | Somente input. Comprimento máximo opcional do valor. |
| default | string | Opcional | Somente input. Valor pré-preenchido opcional. |
Objeto response
Auto-resposta opcional em qualquer Button. Com callback_url, é enviada imediatamente em paralelo ao POST de saída (padrão slow-approval).
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| message | string (≤ 2000) | Obrigatório | Texto de auto-resposta mostrado ao clicker. |
| buttons | array<Button> | Opcional | Botões aninhados recursivos com o mesmo schema Button. Limites: profundidade ≤ 3, ≤ 25 botões/nível, ≤ 16 KiB por botão top-level. Campos Button: Objeto Button ↑. |
| replace_original | boolean | Opcional | Substitui a mensagem original em vez de publicar uma nova. Padrão false. |
| ephemeral | boolean | Opcional | Só Slack; ignorado em outras plataformas. Padrão false. |
Objeto callback_auth
Auth de transporte estática opcional em um Button. Só válida junto com callback_url. Sempre aditiva a X-Dailybot-Signature.
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| type | "bearer" | "basic" | "custom_header" | Obrigatório | Tipo de auth. Exatamente os campos do tipo escolhido — extras são rejeitados (button_callback_auth_invalid). |
| token | string (≤ 4096) | Opcional | Obrigatório para type: "bearer". Enviado como Authorization: Bearer <token>. |
| username | string | Opcional | Obrigatório para type: "basic" (com password). Enviado como Authorization: Basic <base64>. |
| password | string | Opcional | Obrigatório para type: "basic" (com username). |
| header_name | string (RFC 7230 token) | Opcional | Obrigatório para type: "custom_header". Nomes negados: host, content-length, content-type, transfer-encoding, connection, user-agent, e qualquer coisa que comece com x-dailybot-. |
| header_value | string | Opcional | Obrigatório para type: "custom_header". Enviado como <header_name>: <header_value>. |
Resposta
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| bot_message_id | string | Obrigatório | O ID que você enviou, ou um gerado $db/<uuid>. Reutilize em 72h para editar. |
| thread_responses | array<string> | Opcional | IDs de respostas em thread (só se você enviou thread_responses). Cada um se edita como bot_message_id. |
Erros
| Status | Quando |
|---|---|
| 400 | Erro de validação — veja o campo `code`: button_link_and_callback_conflict, button_callback_conflict, button_callback_url_invalid, button_modal_body_invalid, button_callback_form_not_found, button_callback_command_invalid, button_callback_prompt_invalid, button_callback_workflow_not_found, button_response_invalid, button_callback_auth_invalid, buttons_count_out_of_range; além de send_as_user_conflict, send_as_user_invalid_uuid, send_as_user_not_found, invalid_thread_responses, missing_targets. |
| 401 | Credencial ausente, inválida ou expirada. |
| 403 | Autenticado, mas sem permissão — `org_admin_required` quando um não-admin usa `send_as_user`; o scoping por role da CLI retorna `cli_send_message_target_not_allowed`. |
| 429 | Rate-limit atingido. Respeite o header `Retry-After`. |
curl -sS -X POST 'https://api.dailybot.com/v1/send-message/' \
-H 'X-API-KEY: $DAILYBOT_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"message":"Deploy done","target_channels":["C0123456789"]}'curl -sS -X POST 'https://api.dailybot.com/v1/send-message/' \
-H 'X-API-KEY: $DAILYBOT_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"message":"Deploy finished","target_channels":["C0123456789"]}'curl -sS -X POST 'https://api.dailybot.com/v1/send-message/' \
-H 'X-API-KEY: $DAILYBOT_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"message":"Daily report - 2026-07-24","target_channels":["C0123456789"],"bot_message_id":"daily-report-2026-07-24","thread_responses":[{"message":"alice: shipped the billing migration"},{"message":"bob: on PTO, no updates"}]}'curl -sS -X POST 'https://api.dailybot.com/v1/send-message/' \
-H 'X-API-KEY: $DAILYBOT_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"message":"New release is live","target_channels":["C0123456789"],"buttons":[{"label":"Release notes","button_type":"link","url":"https://dailybot.com/changelog"},{"label":"Docs","button_type":"link","url":"https://dailybot.com/developers"}]}'curl -sS -X POST 'https://api.dailybot.com/v1/send-message/' \
-H 'X-API-KEY: $DAILYBOT_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"message":"Deploy to production - approve?","target_users":["U0123456789"],"buttons":[{"label":"Approve","button_type":"interactive","value":"approve","callback_url":"https://ci.example.com/dailybot/approve","callback_auth":{"type":"bearer","token":"$DEPLOY_CALLBACK_TOKEN"},"response":{"message":"Approved - deploying now."}},{"label":"Reject","button_type":"interactive","value":"reject","callback_url":"https://ci.example.com/dailybot/approve","callback_auth":{"type":"bearer","token":"$DEPLOY_CALLBACK_TOKEN"},"response":{"message":"Rejected."}}]}'curl -sS -X POST 'https://api.dailybot.com/v1/send-message/' \
-H 'X-API-KEY: $DAILYBOT_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"message":"Pick a follow-up action","target_users":["U0123456789"],"buttons":[{"label":"Submit expense","button_type":"interactive","value":"expense_form","callback_form":"$EXPENSE_FORM_UUID"},{"label":"Trigger rollback","button_type":"interactive","value":"rollback","callback_workflow":"$ROLLBACK_WORKFLOW_UUID"},{"label":"Run help","button_type":"interactive","value":"help","callback_command":"help"},{"label":"Summarize thread","button_type":"interactive","value":"summarize","callback_prompt":"Summarize the last 20 messages in this channel."}]}'curl -sS -X POST 'https://api.dailybot.com/v1/send-message/' \
-H 'X-API-KEY: $DAILYBOT_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"message":"Log a quick update","target_users":["U0123456789"],"buttons":[{"label":"Add update","button_type":"interactive","value":"log_update","callback_url":"https://ci.example.com/dailybot/log-update","modal_body":{"title":"Log an update","submit_label":"Save","blocks":[{"type":"text","text":"Share a quick status update."},{"type":"input","name":"update_text","label":"Update","multiline":true,"required":true},{"type":"divider"}]}}]}'Testar
Este é um ajudante apenas de cópia — a requisição não é enviada do seu navegador. Cole o comando no seu terminal para executá-lo.
- Threads: passe `thread_responses` (máx. 10) para publicar pai + respostas em uma única chamada. Responda a uma mensagem existente adicionando `thread` dentro de um objeto em `target_channels`: `{ id, thread: <ts_ou_id_pai> }`.
- Editar: reenvie com o mesmo `bot_message_id` em até 72h. Campos de identidade (`bot_username`, `bot_icon_*`) são ignorados na edição — a plataforma mantém a identidade original.
- Impersonação: `platform_settings.bot_username` mais `bot_icon_url` OU `bot_icon_emoji` mudam a aparência do bot para essa mensagem. Apenas Slack hoje; outras plataformas ignoram o bloco de identidade.
- Ephemeral (só Slack): use `platform_settings.is_ephemeral: true` junto com `target_users` para enviar uma mensagem privada dentro do canal, visível somente para esses usuários.
- Scoping por role da CLI: admin/manager alcança qualquer usuário/time/canal público; membro de time alcança colegas + canais públicos; convidado só envia mensagens para si mesmo.
- Multi-plataforma: funciona no Slack, Microsoft Teams, Discord e Google Chat. O threading em DMs varia — Teams / Discord / Google Chat publicam planos em DMs.
- Botões interativos: os cinco callbacks (`callback_url`, `callback_form`, `callback_command`, `callback_prompt`, `callback_workflow`) são mutuamente exclusivos em um único botão (`button_callback_conflict`). `modal_body` combina com `callback_url` OU `callback_workflow` (não com callbacks internos). Auto-respostas `response` combinam com qualquer forma de botão.
- Callbacks assinados: botões com `callback_url` recebem POSTs assinados com HMAC via `X-Dailybot-Signature` (e `X-Dailybot-Event`, `X-Dailybot-Delivery`, `X-Dailybot-Timestamp`). Google Chat é reportado como plataforma `hangouts` no corpo do callback — compare com esse valor, não com "gchat" ou "googlechat".
- Consulte a seção Interactive buttons na página para snippets de verificação de assinatura (Node.js / Python), o schema de blocos de `modal_body`, a matriz de compatibilidade e os tipos de callback-auth.
Open a conversation (API-Key only)
Open a conversation (API-Key only)
Erros
| Status | Quando |
|---|---|
| 401 | Missing/invalid/expired credential |
| 403 | Authenticated but not permitted |
| 429 | Throttled - Retry-After header set |
| 400 | Validation error |
curl -sS -X POST 'https://api.dailybot.com/v1/open-conversation/' -H 'X-API-KEY: $DAILYBOT_API_KEY'Testar
Este é um ajudante apenas de cópia — a requisição não é enviada do seu navegador. Cole o comando no seu terminal para executá-lo.
Send an email (API-Key only)
Body: to, subject, body_html, body_text.
Erros
| Status | Quando |
|---|---|
| 401 | Missing/invalid/expired credential |
| 403 | Authenticated but not permitted |
| 429 | Throttled - Retry-After header set |
| 400 | Validation error |
curl -sS -X POST 'https://api.dailybot.com/v1/send-email/' -H 'X-API-KEY: $DAILYBOT_API_KEY'Testar
Este é um ajudante apenas de cópia — a requisição não é enviada do seu navegador. Cole o comando no seu terminal para executá-lo.
A API pública do Dailybot expõe endpoints de mensageria para entregar mensagens do bot, emails e conversas privadas no Slack, Microsoft Teams, Discord e Google Chat. Esta página inclui as tabelas de campos estruturadas de POST /v1/send-message/, POST /v1/send-email/ e POST /v1/open-conversation/ (incluindo o contrato completo de Button / modal_body / response / callback_auth), além da substituição de identidade send_as_user e o guia detalhado de botões interativos.
Construtor de botões
Abaixo da referência de send-message, um Construtor de botões interativo permite compor botões visualmente — de link, simples, aprovar/rejeitar, gatilho de workflow, formulário, comando, prompt e modal — e copiar o array buttons JSON exato, o comando dailybot chat send equivalente (usando --link-button, --button, --approve-button/--reject-button com --callback-url/--callback-bearer, ou --workflow-button, recorrendo a --buttons '<json>' para o que esses flags não conseguem expressar), ou um body de curl pronto para executar contra POST /v1/send-message/.
Substituição de identidade send_as_user (apenas Slack)
send_as_user permite que um chamador autorizado publique uma mensagem que parece vir de outro usuário — a mensagem exibe o nome de exibição e o avatar do Slack desse usuário em vez da identidade do bot. É útil para workflows automatizados que precisam apresentar mensagens na perspectiva de um membro específico da equipe.
Requisitos:
- O chamador deve ser administrador da organização ou ter uma chave de propriedade de um administrador.
- O usuário alvo (UUID de
send_as_user) deve estar ativo e na mesma organização. - Aplica-se apenas no Slack — outras plataformas ignoram o campo e voltam à identidade padrão do bot.
send_as_useré mutuamente exclusivo combot_username,bot_icon_urlebot_icon_emoji. Combiná-los retorna400comcode: "send_as_user_conflict".
Quando send_as_user está definido, o Dailybot busca a identidade do Slack conectada do usuário e a usa como autora da mensagem. A mensagem ainda é enviada pelo token do bot do Dailybot — não usa o token do Slack do usuário.
curl -X POST "https://api.dailybot.com/v1/send-message/" \
-H "X-API-KEY: $DAILYBOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "The sprint is closed and all tickets are resolved.",
"target_channels": ["C0123456789"],
"send_as_user": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}'
Códigos de erro para send_as_user:
code |
HTTP | Quando |
|---|---|---|
send_as_user_conflict |
400 | send_as_user combinado com bot_username, bot_icon_url ou bot_icon_emoji |
send_as_user_invalid_uuid |
400 | O formato do UUID é inválido |
send_as_user_not_found |
400 | Usuário não encontrado, inativo ou em outra organização |
org_admin_required |
403 | O chamador não é administrador |
Botões interativos
Cada mensagem pode carregar até 25 botões renderizados como elementos interativos nativos no Slack, Microsoft Teams, Discord e Google Chat. Dois valores de button_type são suportados:
link— ao clicar abre aurlno navegador do usuário.interactive— ao clicar aciona uma das quatro capacidades descritas abaixo.
Campos do botão
| Campo | Tipo | Quando | Notas |
|---|---|---|---|
label |
string (≤ 40 chars) |
obrigatório | Renderizado no botão. |
label_after_click |
string (≤ 40) |
opcional | Substitui label após o clique. Padrão: label. |
button_type |
"link" | "interactive" |
obrigatório | Veja abaixo. |
url |
string (https) |
obrigatório quando button_type = "link" |
A URL que o usuário abre. |
value |
string (≤ 2000) |
obrigatório quando button_type = "interactive" |
Enviado de volta no corpo do POST de callback para o chamador saber qual botão foi clicado. |
callback_url |
string (https, ≤ 2048) |
opcional (interactive) | URL de callback que recebe um POST assinado no clique e no envio do modal. Mutuamente exclusivo com callback_form e callback_command. Veja URLs de callback interativas abaixo. |
modal_body |
object |
opcional (interactive) | Abre um modal no clique. Requer callback_url se o modal tiver campos de entrada. Veja Botões modais abaixo. |
callback_form |
string (form UUID) |
opcional (interactive) | Aciona um formulário interno do Dailybot, referenciado pelo UUID. Mutuamente exclusivo com callback_url e callback_command. Veja Gatilhos de formulários internos abaixo. |
callback_command |
string (≤ 200) |
opcional (interactive) | Aciona um comando interno CONHECIDO do Dailybot (ex.: help). O prefixo legado "prompt: …" é rejeitado — use callback_prompt. Mutuamente exclusivo com os outros callbacks. |
callback_prompt |
string (≤ 2000) |
opcional (interactive) | Prompt de IA em texto livre executado como o usuário que clica. Mutuamente exclusivo com os outros callbacks. Veja Gatilhos de prompts de IA abaixo. |
callback_workflow |
string (workflow UUID) |
opcional (interactive) | Aciona um workflow interno do Dailybot, referenciado pelo UUID. Mutuamente exclusivo com os outros callbacks. Veja Gatilhos de workflows abaixo. |
response |
object |
opcional | Resposta automática ao usuário que clica: {message (≤2000, required), buttons? (recursive), replace_original?, ephemeral?}. Compõe com QUALQUER forma de botão. Veja Respostas automáticas abaixo. |
callback_auth |
object |
opcional (requer callback_url) |
Auth de transporte estática para o POST de saída (bearer | basic | custom_header) — aditiva à assinatura HMAC sempre ativa. Veja Autenticação de callback abaixo. |
destroy_button |
bool |
opcional (padrão true) |
Quando false, o botão permanece clicável após o primeiro clique. |
platform_settings |
object |
opcional | Overrides por plataforma (raramente necessários). |
payload |
object |
opcional | Payload extra livre; opaco para a API. Os novos campos acima devem ficar no nível superior, não dentro de payload. |
Todo botão interativo do lado do servidor carrega um button_id = "$btn/<uuid4>" gerado pelo servidor que é ecoado em todo corpo de callback para o chamador identificar cada clique de forma única. Valores de button_id fornecidos pelo cliente são silenciosamente sobrescritos.
Nota de compatibilidade: payload.callback_config e campos value de ações de integrações antigas ainda funcionam e são aditivos — prefira os campos de nível superior acima para novas integrações.
Matriz de compatibilidade
✔ = permitidos juntos, ✖ = rejeitado. Os cinco callbacks são mutuamente exclusivos entre si (button_callback_conflict).
callback_url |
callback_form |
callback_command |
callback_prompt |
callback_workflow |
modal_body |
response |
|
|---|---|---|---|---|---|---|---|
callback_url |
— | ✖ | ✖ | ✖ | ✖ | ✔ | ✔ |
callback_form |
✖ | — | ✖ | ✖ | ✖ | ✖ | ✔ |
callback_command |
✖ | ✖ | — | ✖ | ✖ | ✖ | ✔ |
callback_prompt |
✖ | ✖ | ✖ | — | ✖ | ✖ | ✔ |
callback_workflow |
✖ | ✖ | ✖ | ✖ | — | ✔ | ✔ |
modal_body |
✔ | ✖ | ✖ | ✖ | ✔ | — | ✔ |
response |
✔ | ✔ | ✔ | ✔ | ✔ | ✔ | — |
Um modal com blocos input requer callback_url OU callback_workflow (400 button_modal_body_invalid, detail input_without_callback).
label_after_click e destroy_button compõem com tudo (incluindo response): destroy_button: false mantém o botão clicável — cada clique é um novo despacho com um id X-Dailybot-Delivery novo; em botões modais a troca de label_after_click ocorre no ENVIO do modal, não na abertura, então um modal cancelado deixa o botão clicável. Um botão interativo simples pode carregar response sem nenhum callback (o caso “Skip”).
URLs de callback interativas
Um botão interactive com callback_url recebe um HTTP POST do Dailybot quando o usuário clica. É a forma canônica para fluxos de aprovação, feedback e triagem leve construídos sobre /v1/send-message/.
Exemplo de requisição:
curl -X POST "https://api.dailybot.com/v1/send-message/" \
-H "X-API-KEY: $DAILYBOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Juan wants to buy a coffee. Approve?",
"target_users": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],
"buttons": [
{ "label": "Yes", "button_type": "interactive", "value": "approve",
"callback_url": "https://approvals.acme.example/v1/decisions/req_9812" },
{ "label": "No", "button_type": "interactive", "value": "deny",
"callback_url": "https://approvals.acme.example/v1/decisions/req_9812" }
]
}'
Corpo do POST de callback — o Dailybot dispara isto quando o usuário clica:
POST https://approvals.acme.example/v1/decisions/req_9812
Content-Type: application/json
User-Agent: Dailybot-Chatbot/1.0
X-Dailybot-Event: button_click
X-Dailybot-Delivery: 5e2d…-uuid
X-Dailybot-Timestamp: 1782001872
X-Dailybot-Signature: t=1782001872, v1=6d9a3e…hex_hmac
{
"event": "button_click",
"bot_message_id": "$db/ae007b43-dde2-4fa9-bce3-71fb0975a249",
"button": { "id": "$btn/…", "value": "approve" },
"user": { "id": "…", "email": "…", "display_name": "…", "external_id": "U01ABCDEFG" },
"organization": { "id": "…", "name": "…" },
"platform": "slack",
"channel": { "id": "D0123456", "type": "im" },
"modal_fields": null,
"metadata": { "campaign": "coffee-approvals" },
"sent_at": "2026-07-22T14:30:00Z",
"clicked_at": "2026-07-22T14:31:12Z"
}
Valores de platform. Um de slack, msteams, discord ou hangouts. O Google Chat é entregue como hangouts (o identificador histórico de plataforma) — corresponda a esse valor, não a “gchat” ou “googlechat”. sent_at é marcado quando a mensagem da plataforma foi realmente entregue; clicked_at quando o usuário clicou. metadata retorna verbatim da sua chamada original a /v1/send-message/.
Verificação de assinatura. Todo POST carrega uma assinatura HMAC-SHA256 calculada com o segredo de assinatura de callback da sua organização sobre a string ASCII "{unix_timestamp}.{raw_body}".
Node.js:
const crypto = require('crypto');
function verify(rawBody, sigHeader, secretB64) {
const secret = Buffer.from(secretB64, 'base64url');
const parts = Object.fromEntries(sigHeader.split(',').map(s => s.trim().split('=')));
const ts = parseInt(parts.t, 10);
if (Math.abs(Date.now()/1000 - ts) > 300) return false;
const expected = crypto.createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(parts.v1, 'hex'));
}
Python:
import hmac, hashlib, base64, time
def verify(raw_body: bytes, sig_header: str, secret_b64: str) -> bool:
secret = base64.urlsafe_b64decode(secret_b64 + '==')
parts = dict(p.strip().split('=', 1) for p in sig_header.split(','))
ts = int(parts['t'])
if abs(time.time() - ts) > 300: # 5 min replay window
return False
expected = hmac.new(secret, f"{ts}.{raw_body.decode()}".encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts['v1'])
Idempotência. X-Dailybot-Delivery é único por tentativa de clique. Se o POST de saída do Dailybot for reenviado, o mesmo id de entrega é enviado — use-o como chave de deduplicação.
Reenvios. O Dailybot reenvia uma vez com backoff de 500 ms em erros 5xx / 429 / de rede. 2xx bem-sucedido completa o fanout; qualquer outro 4xx é tratado como terminal e descartado.
Botões modais
Adicione um objeto modal_body a um botão interactive para abrir um modal leve no clique. No envio, os valores de entrada do modal são publicados em callback_url junto com event: "modal_submit" e o value do botão clicado.
Esquema de modal_body:
Os tipos de bloco suportados são exatamente text, input e divider. O modal_body serializado deve ser ≤ 8 KiB. Valores name de entrada devem corresponder a ^[a-z][a-z0-9_]{0,62}$ e ser únicos dentro do modal.
{
"title": "string, ≤ 200 chars, required",
"submit_label": "string, ≤ 200 chars, default 'Submit'",
"blocks": [
// 1..10 blocks; supported block types:
{ "type": "text", "text": "≤ 3000 chars" },
{
"type": "input",
"name": "snake_case_identifier", // required, unique per modal; regex ^[a-z][a-z0-9_]{0,62}$
"label": "Field label, ≤ 200", // required
"multiline": true, // optional, default false
"required": true, // optional, default false
"max_length": 1000, // optional, ≤ 3000
"placeholder": "≤ 200", // optional
"default": "prefilled value" // optional
},
{ "type": "divider" }
]
}
Exemplo de requisição (aprovar com comentário):
curl -X POST "https://api.dailybot.com/v1/send-message/" \
-H "X-API-KEY: $DAILYBOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Sprint retro — how did it feel?",
"target_teams": ["team_engineering_uuid"],
"buttons": [
{ "label": "🚀 Great", "button_type": "interactive", "value": "great",
"callback_url": "https://retros.acme.example/v1/sprint-42" },
{ "label": "😐 Fine", "button_type": "interactive", "value": "fine",
"callback_url": "https://retros.acme.example/v1/sprint-42" },
{
"label": "📝 Add feedback",
"button_type": "interactive",
"value": "feedback",
"callback_url": "https://retros.acme.example/v1/sprint-42",
"modal_body": {
"title": "Sprint feedback",
"submit_label": "Send",
"blocks": [
{ "type": "text", "text": "Anything on your mind about this sprint?" },
{
"type": "input",
"name": "sentiment_note",
"label": "Your feedback",
"multiline": true,
"required": true,
"max_length": 1000,
"placeholder": "One or two sentences is perfect."
}
]
}
}
]
}'
Corpo do POST de envio de modal (o Dailybot publica isto em callback_url):
{
"event": "modal_submit",
"bot_message_id": "$db/…",
"button": { "id": "$btn/…", "value": "feedback" },
"user": { "id": "…", "email": "…", "display_name": "…", "external_id": "U…" },
"organization": { "id": "…", "name": "…" },
"platform": "slack",
"channel": { "id": "C…", "type": "channel" },
"modal_fields": {
"sentiment_note": "Retro was great, ship-per-day cadence is working."
},
"metadata": { },
"sent_at": "2026-07-22T14:30:00Z",
"clicked_at": "2026-07-22T14:31:12Z"
}
Mesmos cabeçalhos / assinatura que button_click; apenas event e modal_fields diferem.
Modais somente de exibição (blocos contêm apenas text e divider, sem input) são permitidos sem callback_url — clicar em Submit apenas fecha o modal e nenhum POST é disparado.
Gatilhos de formulários internos
Um botão interactive com callback_form abre um formulário do Dailybot no clique. Nenhum serviço externo é chamado; o callback_url do chamador é ignorado (e rejeitado se ambos estiverem definidos).
curl -X POST "https://api.dailybot.com/v1/send-message/" \
-H "X-API-KEY: $DAILYBOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Need to request access to a system?",
"target_channels": ["C0AF0FBT23D"],
"buttons": [
{ "label": "Open access-request form",
"button_type": "interactive",
"value": "open_access_form",
"callback_form": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }
]
}'
callback_form deve ser o UUID de um formulário do Dailybot na organização do chamador (liste seus formulários via /v1/forms/ para encontrá-lo). Nomes e slugs são rejeitados — nomes de formulário são mutáveis e ambíguos. Formulários desconhecidos, arquivados ou inacessíveis → 400 button_callback_form_not_found. O formulário é preenchido pelo usuário pelo fluxo de formulários existente — veja /v1/forms/ para ler as respostas resultantes.
Gatilhos de comandos internos
Um botão interactive com callback_command executa um comando interno CONHECIDO do Dailybot no clique (ex.: help, kudos, checkin). Máx. 200 caracteres.
curl -X POST "https://api.dailybot.com/v1/send-message/" \
-H "X-API-KEY: $DAILYBOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Need help getting started?",
"target_users": ["…"],
"buttons": [
{ "label": "Open help",
"button_type": "interactive",
"value": "help",
"callback_command": "help" }
]
}'
Sem prefixo prompt:. A convenção legada "prompt: <text>" foi removida. Um callback_command que começa com prompt: (sem distinção de maiúsculas) é rejeitado com 400 button_callback_command_invalid — use o campo dedicado callback_prompt.
Atribuição. O comando roda sob a identidade do usuário que clica (escopo de papel, atribuição de uso) — não do remetente. Chamadores não podem usar callback_command para fazer outro usuário executar um comando que não tem permissão.
Comandos desconhecidos (não na lista de comandos integrados) falham suavemente com uma resposta localizada “That command isn’t available” ao usuário que clicou — sem erro para o remetente.
Gatilhos de prompts de IA
Um botão interactive com callback_prompt envia um prompt de texto livre (≤ 2000 caracteres) ao assistente de IA do Dailybot no clique, atribuído ao usuário que clica (sua cota de IA, suas permissões).
curl -X POST "https://api.dailybot.com/v1/send-message/" \
-H "X-API-KEY: $DAILYBOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Curious about last week?",
"target_users": ["…"],
"buttons": [
{ "label": "Ask the assistant",
"button_type": "interactive",
"value": "ask_ai",
"callback_prompt": "Summarize incidents from the past 7 days." }
]
}'
Prompts em branco ou acima do tamanho → 400 button_callback_prompt_invalid.
Gatilhos de workflows
Um botão interactive com callback_workflow aciona um workflow interno do Dailybot no clique, atribuído ao usuário que clica. callback_workflow deve ser o UUID de um workflow na organização do chamador — nomes/slugs são rejeitados. O workflow deve existir, pertencer à organização e estar ativo; caso contrário 400 button_callback_workflow_not_found.
curl -X POST "https://api.dailybot.com/v1/send-message/" \
-H "X-API-KEY: $DAILYBOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Deploy is ready.",
"target_users": ["…"],
"buttons": [
{ "label": "Run release workflow",
"button_type": "interactive",
"value": "run_release",
"callback_workflow": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }
]
}'
Nenhum POST externo é disparado e nenhum material de assinatura está envolvido — o gatilho é totalmente interno.
Variáveis de gatilho. Passos do workflow acionado podem referenciar o contexto do clique pelo namespace {{trigger.*}}: {{trigger.source}} (api | button_click | modal_submit), {{trigger.button_value}}, {{trigger.button_id}}, {{trigger.fields.<name>}} (entradas do modal), {{trigger.clicked_at}}, {{trigger.body.*}} (payload bruto), {{trigger.user.*}} (uuid, full_name, first_name, email, role do usuário que clicou) e {{trigger.triggered_by_user_uuid}}. Para ramificação simples por valor, aponte vários botões ao MESMO workflow com values diferentes e ramifique em {{trigger.button_value}}. Veja /developers/api/workflows para a referência completa de variáveis de gatilho.
Modal → Workflow
modal_body compõe com callback_workflow: o clique abre o modal e, no envio, os valores dos campos são entregues ao workflow como {{trigger.fields.<input.name>}} — sem servidor externo.
curl -X POST "https://api.dailybot.com/v1/send-message/" \
-H "X-API-KEY: $DAILYBOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Report an incident:",
"target_users": ["…"],
"buttons": [
{ "label": "Report", "button_type": "interactive", "value": "report",
"callback_workflow": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"modal_body": {
"title": "New incident",
"blocks": [
{ "type": "input", "name": "summary", "label": "What happened?",
"multiline": true, "required": true }
]
} }
]
}'
O workflow (tipo de gatilho api_trigger) pode então usar {{trigger.fields.summary}} em qualquer passo — pré-preencher uma resposta de formulário, compor uma mensagem, alimentar um prompt de IA. Botões modal-para-workflow não carregam segredo de assinatura (rota interna). Um modal com blocos input e SEM callback_url nem callback_workflow é rejeitado (input_without_callback).
Respostas automáticas
Qualquer botão (incluindo um botão interativo simples sem callback) pode carregar um objeto response — uma resposta automática mostrada ao usuário que clica:
{
"message": "string — required, ≤ 2000 chars",
"buttons": [],
"replace_original": false,
"ephemeral": false
}
O caso “Skip” — um botão cuja única função é reconhecer:
curl -X POST "https://api.dailybot.com/v1/send-message/" \
-H "X-API-KEY: $DAILYBOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Time for your weekly reflection!",
"target_users": ["…"],
"buttons": [
{ "label": "Start", "button_type": "interactive", "value": "start",
"callback_form": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" },
{ "label": "Skip this week", "button_type": "interactive", "value": "skip",
"response": { "message": "No problem — see you next week! 👋" } }
]
}'
Momento. Com callback_url, a resposta é enviada imediatamente no clique, em paralelo com o POST de saída — é feedback instantâneo ao usuário (“Processing your approval…”), nunca condicionado ao resultado do despacho. Este é o padrão canônico de aprovação lenta: reconhecer instantaneamente via response, depois seu servidor acompanhar no próprio ritmo com um novo POST /v1/send-message/ ou editando a mensagem original dentro da janela de 72 h de bot_message_id. Com modal_body, a resposta é enviada após o ENVIO do modal. Com os callbacks internos (callback_form / callback_command / callback_prompt / callback_workflow), a resposta é enviada ANTES da entrega.
replace_original — substitui a mensagem de origem em vez de publicar uma nova. ephemeral — apenas Slack; ignorado em outros lugares.
Botões recursivos. response.buttons usa o mesmo esquema Button e é validado recursivamente: profundidade máxima de aninhamento 3, ≤ 25 botões por nível, button_id gerado pelo servidor em cada profundidade e um limite de tamanho serializado total de 16 KiB por botão de nível superior. Violações → 400 button_response_invalid com detail um de response_message_required, response_message_too_long, nesting_too_deep, too_many_buttons, button_too_large.
Autenticação de callback
Todo POST de callback é SEMPRE assinado com o cabeçalho HMAC X-Dailybot-Signature (veja Segredo de assinatura de callback). Se seu endpoint adicionalmente exige credenciais estáticas — token de API gateway, basic auth, cabeçalho fixo — anexe um objeto callback_auth. Só é válido junto com callback_url.
curl -X POST "https://api.dailybot.com/v1/send-message/" \
-H "X-API-KEY: $DAILYBOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Approve the vendor payment?",
"target_users": ["…"],
"buttons": [
{ "label": "Approve", "button_type": "interactive", "value": "approve",
"callback_url": "https://approvals.acme.example/v1/req_77",
"callback_auth": { "type": "bearer", "token": "acme-gw-token-…" } }
]
}'
Tipos (exatamente os campos do tipo escolhido — extras são rejeitados):
type |
Campos | Enviado como |
|---|---|---|
bearer |
token (≤ 4096) |
Authorization: Bearer <token> |
basic |
username, password |
Authorization: Basic <base64> |
custom_header |
header_name, header_value |
<header_name>: <header_value> |
header_name deve ser um token de cabeçalho RFC 7230 válido e não pode ser um de host, content-length, content-type, transfer-encoding, connection, user-agent, nem qualquer coisa que comece com x-dailybot-. Violações → 400 button_callback_auth_invalid.
Credenciais são somente de escrita: nunca são retornadas por nenhuma API de leitura e nunca aparecem em logs. A assinatura HMAC permanece obrigatória — verifique-a mesmo quando também exigir auth estática.
Códigos de erro de botões interativos
Todos são HTTP 400. A forma da resposta segue o envelope existente ({ "detail": "…", "code": "…" }).
code |
Quando |
|---|---|
button_link_and_callback_conflict |
Um botão link foi combinado com value, modal_body, response, callback_auth ou qualquer campo de callback. |
button_callback_conflict |
Um botão interactive combina mais de um de callback_url, callback_form, callback_command, callback_prompt, callback_workflow, ou combina modal_body com um callback interno. |
button_callback_url_invalid |
callback_url sem esquema, não https, malformada, maior que 2048 caracteres ou resolve para um intervalo privado / loopback / IMDS. |
button_modal_body_invalid |
modal_body falhou na validação estrutural — tipo de bloco incorreto, ≥ 11 blocos, name ausente / duplicado, campo grande demais, ou modal com entradas mas sem callback_url / callback_workflow (input_without_callback). |
button_callback_form_not_found |
callback_form não resolve para um formulário na organização do chamador. |
button_callback_command_invalid |
callback_command tem mais de 200 caracteres ou usa o prefixo prompt: removido (use callback_prompt). |
button_callback_prompt_invalid |
callback_prompt está em branco ou tem mais de 2000 caracteres. |
button_callback_workflow_not_found |
callback_workflow não é um UUID ou não resolve para um workflow ativo na organização do chamador. |
button_response_invalid |
response falhou na validação — veja detail: response_message_required, response_message_too_long, nesting_too_deep, too_many_buttons, button_too_large. |
button_callback_auth_invalid |
callback_auth sem callback_url, tipo desconhecido, campos incorretos/extra ou header_name negado/inválido. |
Os comportamentos existentes relacionados a botões (limite de buttons.length de 25, erros send_as_user_*, invalid_thread_responses, etc.) permanecem inalterados.
Segredo de assinatura de callback
Cada organização tem um único segredo de assinatura de callback usado para HMAC. É gerado automaticamente na primeira vez que uma mensagem com callback_url é enviada. O segredo nunca é retornado pela API pública; obtenha-o do administrador da sua organização (um endpoint de rotação / recuperação está no roadmap). Guarde-o no armazenamento de segredos do seu serviço; trate-o como um segredo de cliente OAuth.
Veja em ação
Receitas de automação construídas sobre a API send-message, a CLI e a skill de agentes — cada uma com exemplos de curl, CLI e prompts prontos para copiar e colar.