Webhooks by Wakeshift
ai.wakeshift由 wakeshift.ai 发布官方发布者v1.0.0更新于 Nov 4, 2026
A webhook URL that wakes your AI agent: every POST to it wakes the conversation watching it.
发布方自己的服务:Slackline
概览
为 AI 代理提供一个 webhook 网址,任何 POST 都会唤醒正在监听该网址的对话,并提供监听、取消监听和查看近期投递的工具。
- 可以做什么
- 在当前对话中监听或取消监听某个 webhook,使收到的投递唤醒代理
- 查看近期投递记录和 webhook 详情,包括当前使用的校验网址与签名校验方式
- 接收来自 GitHub、Stripe、Linear 或自建应用的解析后请求体、方法、内容类型和标识发送方的请求头
- 按投递 ID 或事件 ID 去重重试,并给出说明发生了什么的一行摘要
- 适用场景
- 适合希望代理被动响应外部事件而非轮询的场景,例如 CI 失败、Stripe 支付事件、Linear 工单变更或自建应用的通知。当对话需要被 webhook 唤醒并据此采取行动时值得添加。
- 运行要求
- 远程 MCP 端点 try.wakeshift.ai,无需登录,链接中的代码本身就是凭证。链接需从站点获取,7 天未使用即过期。自行部署需要 Wakeshift 应用密钥、Postgres 数据库及若干环境变量。
安装
在 SourceWeft 中
- 打开 控制台中的 Webhooks by Wakeshift,将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Web executable,通过 Streamable HTTP。 远程服务在工作区中配置后即可从网页运行时运行。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
Webhooks
A webhook URL that wakes your agent: get a link, add it to your agent (Claude Code, Codex, Cursor, Antigravity, opencode, Copilot CLI or any MCP client), ask the agent to watch, and every POST to your webhook URL (curl, Postman, GitHub, Stripe, Linear, your own app) wakes it. Wakeshift runs it at try.wakeshift.ai. Built on the TypeScript SDK, @wakeshift/sdk.
How it works
- Stateless links. A link's code is signed with
TRY_SECRETand names a random webhook ID and when it was made. The MCP URL (/t/<code>/mcp), the page (/l/<code>), the webhook URLs (/in/<token>, one token per signature check) and the signing secret are all derived from it. Nothing is stored. A link expires after 7 days without use; when it was last used is kept in the database (written at most every 5 minutes per instance). When it expires, Wakeshift is asked to forget the webhook (forgetUserwith the webhook ID, which is the app's user for it): its workspace, the conversations that watched it, their subscriptions and deliveries. The sweep queues it in the database in the transaction that deletes the link's own rows, and every instance works the queue every 10 minutes, retrying a failure with backoff (a minute, doubling, at most 6 hours) until Wakeshift says it's done. - The SDK user is the webhook; posts are an event.
webhook.received(argument: the webhook's ID; only the webhook's own SDK user, anyone with its link, may subscribe) carries what was posted:summary, a line saying what happened, then the parsed body and the headers that say who sent it. Every tool is wrapped withattached.events(the handlewake.attachreturns), and takes Wakeshift's arguments throughattached.inputs.watchsubscribes the calling conversation withcall.subscribe;unwatchends it withcall.unsubscribe. The wrapper adds one Wakeshift block to each tool's result: how the conversation is woken after a subscribe, pending messages and a Codex thread's beacon otherwise. A call that fails ends the subscription it made. A client that speaks MCP Events (ChatGPT) gets no conversation subscription: the block tells it to subscribe towebhook.receiveditself. A post becomesevent.emit.wake.attachaddssubscribe_events,unsubscribe_eventsandlist_subscriptions. - MCP: Streamable HTTP with sessions, no sign-in (the code in the URL is the credential). Nothing about a session lives in an instance: initialize's client name, version and capabilities are stored under the
Mcp-Session-Id, and each request builds the MCP server afresh from them on whichever instance it reaches (the SDK's transport in stateless mode; the session ID is checked here, 404 if unknown or another link's). So sessions survive restarts and need no affinity, and the client's name and capabilities (which decide how Cursor, opencode and the rest are woken, and whether a client subscribes itself) are right on every instance: the rebuilt server answersgetClientVersionandgetClientCapabilitiesfrom the stored initialize, and the wrapper reads them. Sessions idle for 7 days are dropped (the client initializes again). Tools:watch,unwatch,recent_posts,webhook_info. - Webhooks:
POST,PUTorPATCH/in/<token>, any body up to 64 KB. The event'stextsays what happened: for GitHub (fromX-GitHub-Event)GitHub workflow_run completed: failure on main (tests) in acme/api; for StripeStripe invoice.payment_failed: in_…, USD 49.00, open (evt_…, test mode); for LinearLinear Issue create: ENG-123 Checkout page 500s; for anything elsePOST to your webhook(with(empty body)if it was), since the data has the rest: the text doesn't repeat the body, so a small post's data fits on one Monitor line (480 bytes) in full. Itsdatais the parsed body (body, orbody_base64), the method, content type, a few headers that say who sent it (includingLinear-EventandLinear-Delivery; never Authorization, cookies or signatures) and, for Stripe and Linear,source(the event type and ID). Retries are one publish: byIdempotency-Key,X-GitHub-Delivery,Linear-Delivery, or a Stripe event'sevt_ID. On a GitHub, Stripe or Linear URL only the service's own ID counts (Idempotency-Keyisn't signed, so a captured delivery replayed with a fresh one would wake the agent again); a Stripe URL uses only theevt_ID from the signed body.GETexplains how to post; a body more than 256 KB over the limit has its connection dropped rather than read. - Signature checks: the page's tabs give a URL per check, each its own token, so a checked URL can't be turned into the open one; the open URL keeps working for whoever has it, until the user replaces it (below). GitHub's
X-Hub-Signature-256andAuthorization: Beareruse secrets derived per webhook and per check (try_gh_…,try_bearer_…). Stripe and Linear make their own secret: the user pastes it into the page, and it's sealed into that URL's token (AES-256-GCM with a key derived fromTRY_SECRET). It's stored only in that form: the URL is kept as the webhook's checked URL (below) until the link expires. Stripe'sStripe-Signature(t=…,v1=…, HMAC-SHA256 oft.body) must be within 5 minutes; Linear'sLinear-Signature(hex HMAC-SHA256 of the body) needs awebhookTimestampwithin a minute. - A new open URL: the open tab's "Get a new URL" (
POST /l/<code>/rotate) replaces the open URL. Its token then carries the webhook's open-URL generation, kept per webhook in the database (hooks.open_gen), and a post or GET to an open URL of any other generation gets 410 (replaced), on every instance at once. The webhook ID (the SDK user, so its subscriptions), the link and MCP URL, the history and the checked URLs stay as they were, and the live view gets a line saying the URL changed. Only the link's code can ask (a webhook URL is a different capability, and can't), from this site's page: a request whoseOriginorSec-Fetch-Sitesays another site sent it gets 403. Ten an hour per webhook (429 past that). - Which URL the agent hears about:
watchandwebhook_infogive the checked URL the user last picked (a GitHub or bearer tab they opened, a Stripe or Linear URL they made, or the URL a service last posted to), and say which check it uses. It's kept for as long as the link lives. - Limits (counted in the database, atomically, so they hold across instances; fixed windows: the hour and the UTC day): 60 posts an hour and 500 a day for each of a webhook's URLs (429 with
Retry-After), so whoever has the open URL can't use up the checked one's. Refused posts (401, 413) don't count; retries do (each is still a request to Wakeshift, so a repeatedIdempotency-Keycan't get round the limits). 20,000 an hour across all webhooks, 30 new links an hour per address (an IPv6 address by its /64; kept as an HMAC of the address, for the hour).TRY_PER_HOUR,TRY_PER_DAY,TRY_GLOBAL_PER_HOURandTRY_LINKS_PER_HOURchange them, and the terms and privacy policy state the limits in use. - Overload: an instance takes 256 requests in flight (posts three quarters of that, so pages and tool calls keep some room) and 900 open streams (live views, MCP GET and listen streams); for one webhook, at most 20 live views and, apart, 20 agents' streams, so agents can't leave the page without one; 2 GET streams for one MCP session (a live view past that gets 429, a GET stream 405); past that, and when the database is away or out of connections, it answers 503 with
Retry-Afterand a plain message (JSON for webhooks, JSON-RPC for MCP, a page for pages), never a 500. A link's page still comes up when the database is slow, without its history; the live view retries and says so (below). Wakeshift's own 429 or 503 on publish becomes a 503 withRetry-Afterfor the poster. - The page's live view is SSE from this server (
/l/<code>/live): each post (received, refused, rate limited, the start of what was posted, and how many watching conversations the publish reached), and each watch and unwatch. Lines are kept in the database (the last 50 per webhook) and reach pages on every instance byNOTIFYon the webhook's channel (try_<hook>; each instanceLISTENs only for webhooks it has a page open for, and replays the recent lines whenever its connection comes back after a drop; it pings that connection every 30 seconds so a silent drop is noticed). A webhook's refused and rate-limited posts get at most 10 lines a minute per instance, so a flood of bad signatures doesn't push real posts out. The rest are counted, and once the minute is over (or the instance stops) each instance adds its count to the webhook's one line for that minute, which the page updates in place: one line a minute with the total across instances, written at most once a minute per webhook by each instance. A live view that doesn't keep up with what's written to it is dropped (EventSource reconnects). Each line goes with itsseqas its SSE ID, and a live view asks for the lines after the newest it has (?after=<seq>, orLast-Event-IDwhen EventSource reconnects by itself), so after a gap it shows what happened meanwhile (as far as the last 50 go). When the server refuses it (429, 503), EventSource gives up; the page tries again after 2 seconds, doubling to 30 at most (randomized a little), back to 2 once connected, and at once when the page is looked at again, the network comes back or the status poll gets an answer (liveConnectionin page.ts). The page shows who calledwatch, "sent to N watching conversations" per post, and whether an agent is connected right now and how (stream, hooks or polling): it polls/l/<code>/statusevery 10 seconds, which asks Wakeshift forwebhook.received's status with the webhook's ID (event.status, read-only).
Run it yourself
-
In the Wakeshift console, open Build → New app and copy its key (
wst_…). -
Create an empty Postgres database. Webhooks creates its tables when it starts (
migrations/). -
Build the SDK, then Webhooks, from the repository's root:
-
Copy
.env.exampleto.env, fill it in, and run it: -
Open
PUBLIC_URL, get a link, and run the command its tab for your agent shows.
Testing
The end-to-end and load tests run Webhooks against the Wakeshift server, so they run in Wakeshift's own repository.
Contributing
This repository is generated from Wakeshift's main repository. Pull requests are welcome: we apply them there and publish the result. See CONTRIBUTING.
来源:webhooks/README.md,提交 8774523
工具
0版本历史
1- v1.0.0最新Nov 4, 2026
评分
已满足适用检查项的 85%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通必需25 分
- 已声明认证方式必需10 分
- 已列出工具必需15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分