Token导航 LogoToken导航

Agent Skill · 研究检索

webhook-setup(网络钩子设置)

webhook-setup 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

webhook-setup 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证信息还不明确,第三方扫描有提醒项,按安装量在研究检索类的 73,675 个 Skill 里排第 46,976。

总安装 753周安装 32GitHub Stars 1下载 264核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:webhook-setup(网络钩子设置)
来源仓库:https://github.com/zavudev/zavu-skills
仓库路径:skills/webhook-setup
安装命令:
npx skills add https://github.com/zavudev/zavu-skills --skill webhook-setup
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/zavudev/zavu-skills --skill webhook-setup

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

用于查找、检索和筛选相关信息。适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。通过 npx skills add 命令从指定 GitHub 仓库安装,需结合原始 README 核验具体用法。

安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写操作。webhook-setup 属于研究检索类 Skill,可作为该场景下的辅助能力补充。

来源仓库内路径:skills/webhook-setup

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/zavudev/zavu-skills --skill webhook-setup;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

webhook-setup 怎么安装?

在终端执行 npx skills add https://github.com/zavudev/zavu-skills --skill webhook-setup。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

webhook-setup 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

webhook-setup 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

webhook-setup 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

webhook-setup 用的人多吗?

公开数据是累计安装 753 次,近一周安装 32 次,下载 264 次,GitHub 1 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

webhook-setup 安全吗?

第三方扫描有提醒项,说明存在需要人工确认的行为。安装前请打开源码看清它读了什么、联网到哪里。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方扫描存在提醒项或未通过项,需要人工逐条确认。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
webhook-setup

网络钩子设置 · 本页

7531需要联网未明确有提醒

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Webhook Setup

When to Use

Use this skill when setting up webhook endpoints to receive inbound messages, delivery status updates, or template approval notifications from Zavu.

Webhook Types

  • Sender Webhooks: Message events (inbound, delivery status, templates) - configured per sender
  • Project Webhooks: Project-level events (partner invitations) - one per project

Available Events

EventCategoryDescription
message.inboundInboundCustomer sent you a message
conversation.newInboundFirst message from a new contact
message.unsupportedInboundUnsupported message type received
message.queuedOutboundMessage queued for delivery
message.sentOutboundMessage sent to carrier
message.deliveredOutboundMessage delivered to recipient
message.readOutboundMessage read by recipient
message.failedOutboundMessage delivery failed
broadcast.status_changedBroadcastsBroadcast status changed
template.status_changedTemplatesWhatsApp template approval status changed
invitation.status_changedInvitationsPartner invitation status changed

Configure Webhook via SDK

TypeScript - Create Sender with Webhook

const sender = await zavu.senders.create({
  name: "My Sender",
  phoneNumber: "+15551234567",
  webhookUrl: "https://your-app.com/webhooks/zavu",
  webhookEvents: ["message.inbound", "message.delivered", "message.failed"],
});
// Store sender.webhook.secret securely - only shown once!

Update Webhook

await zavu.senders.update({
  senderId: "snd_abc123",
  webhookUrl: "https://new-url.com/webhooks",
  webhookEvents: ["message.inbound"],
  webhookActive: true,
});

Regenerate Secret

const result = await zavu.senders.webhookSecret.regenerate({
  senderId: "snd_abc123",
});
console.log(result.secret); // whsec_new_secret...

Webhook Payload Structure

{
  "id": "evt_1705312200000_abc123",
  "type": "message.inbound",
  "timestamp": 1705312200000,
  "senderId": "snd_abc123",
  "projectId": "prj_xyz789",
  "data": { }
}

Signature Verification

Header: X-Zavu-Signature: t=<timestamp>,v1=<hmac_sha256>

TypeScript (Express)

import crypto from "crypto";
import express from "express";

const app = express();
app.use("/webhooks/zavu", express.raw({ type: "application/json" }));

function verifyZavuSignature(req: express.Request, secret: string): boolean {
  const header = req.headers["x-zavu-signature"] as string;
  if (!header) return false;

  const parts = header.split(",");
  const timestamp = parseInt(parts.find(p => p.startsWith("t="))!.slice(2));
  const signature = parts.find(p => p.startsWith("v1="))!.slice(3);

  // Reject if older than 5 minutes (replay protection)
  if (Math.floor(Date.now() / 1000) - timestamp > 300) return false;

  const signedPayload = `${timestamp}.${req.body.toString()}`;
  const expected = crypto.createHmac("sha256", secret).update(signedPayload).digest("hex");

  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

app.post("/webhooks/zavu", (req, res) => {
  if (!verifyZavuSignature(req, process.env.ZAVU_WEBHOOK_SECRET!)) {
    return res.status(401).send("Invalid signature");
  }

  const event = JSON.parse(req.body.toString());
  res.status(200).send("OK");

  // Process async
  processEvent(event).catch(console.error);
});

async function processEvent(event: any) {
  switch (event.type) {
    case "message.inbound":
      console.log("Inbound from:", event.data.from, event.data.text);
      break;
    case "message.delivered":
      console.log("Delivered:", event.data.messageId);
      break;
    case "message.failed":
      console.log("Failed:", event.data.messageId, event.data.errorMessage);
      break;
  }
}

Python (Flask)

import hmac, hashlib, time
from flask import Flask, request

app = Flask(__name__)

def verify_zavu_signature(req, secret):
    header = req.headers.get("X-Zavu-Signature")
    if not header:
        return False

    parts = header.split(",")
    timestamp = int(next(p for p in parts if p.startswith("t="))[2:])
    signature = next(p for p in parts if p.startswith("v1="))[3:]

    # Reject if older than 5 minutes
    if int(time.time()) - timestamp > 300:
        return False

    signed_payload = f"{timestamp}.{req.data.decode('utf-8')}"
    expected = hmac.new(
        secret.encode(), signed_payload.encode(), hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(expected, signature)

@app.route("/webhooks/zavu", methods=["POST"])
def handle_webhook():
    if not verify_zavu_signature(request, WEBHOOK_SECRET):
        return "Invalid signature", 401

    event = request.json
    # Process event...
    return "OK", 200

Go

package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"io"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

func verifyZavuSignature(r *http.Request, secret string) ([]byte, bool) {
	header := r.Header.Get("X-Zavu-Signature")
	if header == "" {
		return nil, false
	}

	parts := strings.Split(header, ",")
	var timestamp int64
	var signature string
	for _, part := range parts {
		if strings.HasPrefix(part, "t=") {
			timestamp, _ = strconv.ParseInt(part[2:], 10, 64)
		} else if strings.HasPrefix(part, "v1=") {
			signature = part[3:]
		}
	}

	if time.Now().Unix()-timestamp > 300 {
		return nil, false
	}

	body, _ := io.ReadAll(r.Body)
	signedPayload := strconv.FormatInt(timestamp, 10) + "." + string(body)
	h := hmac.New(sha256.New, []byte(secret))
	h.Write([]byte(signedPayload))
	expected := hex.EncodeToString(h.Sum(nil))

	return body, hmac.Equal([]byte(expected), []byte(signature))
}

func main() {
	secret := os.Getenv("ZAVU_WEBHOOK_SECRET")
	http.HandleFunc("/webhooks/zavu", func(w http.ResponseWriter, r *http.Request) {
		body, valid := verifyZavuSignature(r, secret)
		if !valid {
			http.Error(w, "Invalid signature", http.StatusUnauthorized)
			return
		}

		var event map[string]interface{}
		json.Unmarshal(body, &event)
		// Process event...
		w.WriteHeader(http.StatusOK)
	})
	http.ListenAndServe(":3000", nil)
}

Ruby (Sinatra)

require "sinatra"
require "openssl"
require "json"

def verify_zavu_signature(request, secret)
  header = request.env["HTTP_X_ZAVU_SIGNATURE"]
  return false unless header

  parts = header.split(",")
  timestamp = parts.find { |p| p.start_with?("t=") }&.[](2..)&.to_i
  signature = parts.find { |p| p.start_with?("v1=") }&.[](3..)

  return false unless timestamp && signature
  return false if Time.now.to_i - timestamp > 300

  raw_body = request.body.read
  request.body.rewind
  signed_payload = "#{timestamp}.#{raw_body}"
  expected = OpenSSL::HMAC.hexdigest("SHA256", secret, signed_payload)

  Rack::Utils.secure_compare(expected, signature)
end

post "/webhooks/zavu" do
  halt 401, "Invalid signature" unless verify_zavu_signature(request, ENV["ZAVU_WEBHOOK_SECRET"])

  event = JSON.parse(request.body.read)
  # Process event...
  status 200
end

PHP

<?php
function verifyZavuSignature(string $secret): bool {
    $header = $_SERVER['HTTP_X_ZAVU_SIGNATURE'] ?? '';
    if (empty($header)) return false;

    $parts = explode(',', $header);
    $timestamp = $signature = null;
    foreach ($parts as $part) {
        if (str_starts_with($part, 't=')) $timestamp = (int) substr($part, 2);
        elseif (str_starts_with($part, 'v1=')) $signature = substr($part, 3);
    }

    if (!$timestamp || !$signature) return false;
    if (time() - $timestamp > 300) return false;

    $rawBody = file_get_contents('php://input');
    $expected = hash_hmac('sha256', "{$timestamp}.{$rawBody}", $secret);

    return hash_equals($expected, $signature);
}

if (!verifyZavuSignature(getenv('ZAVU_WEBHOOK_SECRET'))) {
    http_response_code(401);
    exit('Invalid signature');
}

$event = json_decode(file_get_contents('php://input'), true);
// Process event...
http_response_code(200);

Retry Policy

AttemptDelay
1st retry1 minute
2nd retry5 minutes
3rd retry15 minutes
4th retry1 hour
5th retry4 hours

After 5 retries, delivery is marked as failed.

Best Practices

  1. Return 200 quickly - respond within 30 seconds, process async
  2. Verify signatures - always verify in production
  3. Idempotent handlers - check event.id to skip duplicates
  4. Use raw body - signature is computed on raw body, not parsed JSON
  5. Test with ngrok - expose local server for development

平台分布

Codex

37.32%
按下载量换算99

Claude

26.47%
按下载量换算70

Cursor

17.48%
按下载量换算46

Gemini CLI

9.1%
按下载量换算24

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

可疑

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在提醒或未通过项,安装前请自行复核。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills