PRO

Webhooks

当计时器启动、暂停或归零时收到通知。连接到 Slack、Zapier 或您自己的后端。

Webhooks

Webhooks 让 Castimer 能够在计时器发生事件时实时通知您的服务器——比如启动、暂停或归零。无需轮询 API,您的服务器会在事件发生的瞬间收到 HTTP POST 请求。

会议计时器结束时发送 Slack 通知
限时促销倒计时归零时自动关闭促销
演示环节结束时自动切换到下一张幻灯片
将计时器完成记录发送到分析平台
游戏或问答中自动开始下一轮

工作原理

1
注册 Webhook URL
2
计时器事件触发
3
Castimer 发送 POST
4
服务器返回 200
5
投递成功

设置 Webhook

在创建或更新计时器时注册 Webhook URL。

curl -X POST https://castimer.com/api/v1/timers \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Flash Sale",
    "type": "event",
    "target_date": "2026-06-01T00:00:00Z",
    "webhook_url": "https://yourapp.com/webhooks/castimer"
  }'

事件类型

事件触发条件
timer.started计时器开始运行
timer.paused计时器被暂停
timer.resumed计时器从暂停状态恢复
timer.completed计时器归零
timer.reset计时器重置为初始时长
interval.round_end间隔计时器的一轮完成
interval.completed间隔计时器所有轮次完成

数据格式

每个 Webhook 都通过 HTTP POST 传递 JSON 数据。Content-Type 为 application/json

{
  "event": "timer.completed",
  "timestamp": "2026-05-10T14:30:00Z",
  "timer_id": "tmr_abc123xyz",
  "title": "Flash Sale Countdown",
  "type": "event",
  "data": {
    "state": "completed",
    "duration": 1800,
    "actual_duration": 1803,
    "started_at": "2026-05-10T14:00:00Z",
    "completed_at": "2026-05-10T14:30:00Z"
  },
  "signature": "sha256=a8f3b2c..."
}
字段类型说明
eventstring事件类型标识符
timestampstring事件发生的 ISO8601 时间
timer_idstring计时器的唯一标识符
titlestring计时器显示标题
typestring计时器类型:countdown、event、interval
dataobject事件特定数据
signaturestring用于请求验证的 HMAC-SHA256 签名

验证请求

请务必验证 Webhook 签名,以确保请求来自 Castimer 且未被篡改。

Castimer 使用 HMAC-SHA256 对每个 Webhook 数据进行签名。签名包含在 X-Castimer-Signature 请求头和数据体的 signature 字段中。

const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');
  
  return `sha256=${expected}` === signature;
}

// In your webhook handler:
app.post('/webhooks/castimer', (req, res) => {
  const signature = req.headers['x-castimer-signature'];
  const isValid = verifyWebhook(req.body, signature, process.env.CASTIMER_WEBHOOK_SECRET);
  
  if (!isValid) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  const { event, timer_id, title } = req.body;
  console.log(`Event: ${event} | Timer: ${title} (${timer_id})`);
  
  res.status(200).json({ received: true });
});

重试机制

如果您的端点返回非 2xx 响应或超时,Castimer 将使用指数退避策略重试投递。

1(首次)立即
21 分钟
35 分钟
430 分钟
52 小时
5 次失败后,投递标记为失败
您的端点必须在 10 秒内返回 200 响应。为避免超时,请立即确认 Webhook 并异步处理事件。

测试 Webhook

使用 webhook.site

  1. 1访问 webhook.site ,您将获得一个唯一的测试 URL
  2. 2通过 API 创建计时器,将该 URL 作为 webhook_url
  3. 3触发计时器事件(启动、完成等)
  4. 4在 webhook.site 实时观察数据到达

使用测试按钮(Dashboard)

在您的控制面板中,可以一键发送测试数据到 Webhook URL。前往 控制面板 → 计时器 → [计时器] → Webhooks → 发送测试

本地开发(ngrok)

# 安装 ngrok 并暴露本地服务
ngrok http 3000

# 使用 ngrok URL 作为 webhook_url
# 例如 https://abc123.ngrok.io/webhooks/castimer

集成示例

发送 Slack 通知

使用 Incoming Webhooks 将计时器事件发送到 Slack 频道。

app.post('/webhooks/castimer', async (req, res) => {
  // Verify signature first (see Verifying Requests)
  
  const { event, title, timer_id } = req.body;
  
  if (event === 'timer.completed') {
    await fetch(process.env.SLACK_WEBHOOK_URL, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        text: `⏰ Timer completed: *${title}*`,
        blocks: [{
          type: 'section',
          text: {
            type: 'mrkdwn',
            text: `⏰ *${title}* has finished!\nTimer ID: \`${timer_id}\``
          }
        }]
      })
    });
  }
  
  res.status(200).json({ received: true });
});

触发 Zapier Webhook

将计时器事件转发到 Zapier 以自动化工作流。

app.post('/webhooks/castimer', async (req, res) => {
  const { event, title, data } = req.body;
  
  if (event === 'timer.completed') {
    // Forward to Zapier catch hook
    await fetch(process.env.ZAPIER_WEBHOOK_URL, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        timer_title: title,
        completed_at: data.completed_at,
        event_type: event
      })
    });
  }
  
  res.status(200).json({ received: true });
});

自动关闭限时促销

当倒计时计时器完成时自动关闭促销。

app.post('/webhooks/castimer', async (req, res) => {
  const { event, timer_id } = req.body;
  
  if (event === 'timer.completed') {
    // Find the sale linked to this timer
    const sale = await db.sales.findOne({ castimer_id: timer_id });
    
    if (sale) {
      // Close the sale automatically
      await db.sales.update(
        { id: sale.id },
        { status: 'closed', closed_at: new Date() }
      );
      
      console.log(`Sale ${sale.id} closed — timer ${timer_id} completed`);
    }
  }
  
  res.status(200).json({ received: true });
});