Objetivo da Aula
Ao concluir esta aula, você será capaz de:
Atualizar status de tarefas no Notion via API com propriedades e timestamps
Enviar notificações formatadas para Slack via webhook
Implementar atualizarStatusNotion(pageId, status, comentario, token) completo
Implementar notificarSlack(mensagem, webhookUrl) com Block Kit
Conectar Notion + Slack em um pipeline automático de atualização
Por que isso importa
Atualizar status no Notion e depois avisar o time no Slack são duas ações manuais que ocorrem dezenas de vezes por semana. Automação elimina o esquecimento — o sistema notifica automaticamente quando uma tarefa muda de status, quem mudou, e qual o próximo passo.
Conceitos Fundamentais
TODO 1: atualizarStatusNotion(pageId, novoStatus, comentario, token)
async function atualizarStatusNotion(pageId, novoStatus, comentario, token) {
// Atualizar propriedades da página
const resProps = await fetch(`https://api.notion.com/v1/pages/${pageId}`, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${token}`,
'Notion-Version': '2022-06-28',
'Content-Type': 'application/json',
},
body: JSON.stringify({
properties: {
Status: { select: { name: novoStatus } },
'Última Atualização': { date: { start: new Date().toISOString() } },
},
}),
})
if (!resProps.ok) {
const erro = await resProps.json()
throw new Error(`Notion API error: ${erro.message}`)
}
// Adicionar comentário como bloco na página (se fornecido)
if (comentario) {
await fetch(`https://api.notion.com/v1/blocks/${pageId}/children`, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${token}`,
'Notion-Version': '2022-06-28',
'Content-Type': 'application/json',
},
body: JSON.stringify({
children: [{
object: 'block',
type: 'callout',
callout: {
icon: { emoji: '📝' },
rich_text: [{
type: 'text',
text: { content: `[${new Date().toLocaleDateString('pt-BR')}] ${comentario}` },
}],
},
}],
}),
})
}
return { sucesso: true, pageId, novoStatus, timestamp: new Date().toISOString() }
}TODO 2: notificarSlack(mensagem, webhookUrl)
async function notificarSlack(mensagem, webhookUrl) {
// Mensagem estruturada com Slack Block Kit
const payload = {
blocks: [
{
type: 'header',
text: { type: 'plain_text', text: mensagem.titulo },
},
{
type: 'section',
fields: [
{ type: 'mrkdwn', text: `*Status:*\n${mensagem.status}` },
{ type: 'mrkdwn', text: `*Responsável:*\n${mensagem.responsavel || 'N/A'}` },
{ type: 'mrkdwn', text: `*Atualizado por:*\n${mensagem.autor}` },
{ type: 'mrkdwn', text: `*Hora:*\n${new Date().toLocaleTimeString('pt-BR')}` },
],
},
...(mensagem.comentario ? [{
type: 'section',
text: { type: 'mrkdwn', text: `💬 ${mensagem.comentario}` },
}] : []),
...(mensagem.link ? [{
type: 'actions',
elements: [{
type: 'button',
text: { type: 'plain_text', text: 'Ver no Notion' },
url: mensagem.link,
style: 'primary',
}],
}] : []),
],
}
const res = await fetch(webhookUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
})
if (!res.ok) throw new Error(`Slack webhook error: ${res.status}`)
return { sucesso: true, status: res.status }
}Aprofundamento Técnico
Slack Block Kit: Elementos Essenciais
Tipo | Uso |
header | Título principal (sem markdown) |
section | Texto ou campos par-a-par |
divider | Linha separadora visual |
actions | Botões clicáveis com URL |
callout | Destaque com ícone (só Notion) |
Slack renderiza emojis nativos: :white_check_mark:, :warning:, :rocket:.
Pipeline Completo
async function atualizarENotificar(pageId, novoStatus, autor, comentario, opts) {
const { notionToken, slackWebhook, pageUrl, responsavel } = opts
// 1. Atualizar Notion
const resultado = await atualizarStatusNotion(pageId, novoStatus, comentario, notionToken)
// 2. Notificar Slack
if (slackWebhook) {
const emoji = novoStatus === 'Concluído' ? '✅' : novoStatus === 'Em Progresso' ? '🔄' : '⏸️'
await notificarSlack({
titulo: `${emoji} Task atualizada: ${novoStatus}`,
status: novoStatus,
responsavel,
autor,
comentario,
link: pageUrl,
}, slackWebhook)
}
return resultado
}Exemplos Anotados
Exemplo 1: Atualização sem credenciais reais (mock)
// No starter.js, se não tiver credenciais:
async function notificarSlackMock(mensagem, webhookUrl) {
console.log('SLACK MOCK — Mensagem que seria enviada:')
console.log(JSON.stringify(mensagem, null, 2))
return { sucesso: true, mock: true }
}
const notificar = process.env.SLACK_WEBHOOK ? notificarSlack : notificarSlackMock
await notificar({ titulo: 'Tarefa concluída', status: 'Concluído', autor: 'Maria' }, url)Padrões e Armadilhas
Padrões
Padrão 1: Idempotência na atualização
// Verificar se já está no status desejado antes de fazer PATCH
const pagina = await fetch(`https://api.notion.com/v1/pages/${pageId}`, { headers })
const status_atual = (await pagina.json()).properties.Status?.select?.name
if (status_atual === novoStatus) return { sucesso: true, sem_mudanca: true }Padrão 2: Fallback gracioso para Slack Se webhook falhar, logar o erro mas não bloquear a atualização do Notion.
Armadilhas
⚠️ Armadilha 1: Notion pageId vs blockId pageId de uma página database tem UUID format: 32char. Blocos dentro da página têm IDs diferentes. Use pageId para propriedades, blockId para adicionar conteúdo.
⚠️ Armadilha 2: Slack webhooks não suportam edição Uma vez enviado, não há como editar mensagem via webhook. Use Slack Bot API se precisar atualizar mensagens.
⚠️ Armadilha 3: Propriedade Notion com nome errado
// Notion é case-sensitive em property names
// "Status" ≠ "status" ≠ "STATUS"
// Verificar o nome exato na UI do NotionSe não for realizar o laboratório, pule para o próximo capítulo.
Ponte para o Lab
TODO 1 — atualizarStatusNotion(pageId, novoStatus, comentario, token): PATCH em /v1/pages/{id} com properties.Status, e PATCH em /v1/blocks/{id}/children para comentário callout.
TODO 2 — notificarSlack(mensagem, webhookUrl): POST para webhook com Block Kit (header, section fields, button de link).
Agora você está pronto para o lab.