GitHub webhook-signature verifier plugin for the TAI ecosystem: a per-provider WebhookVerifier that checks each delivery’s X-Hub-Signature-256 HMAC before the payload is dispatched.
Webhook verifier — Verify a GitHub webhook delivery’s X-Hub-Signature-256 HMAC before dispatch.Registers the github webhook verifier. It authenticates an inbound delivery’s
X-Hub-Signature-256 HMAC-SHA256, computed over the exact raw request body and keyed
by the webhook’s shared secret. Bind it to a hook topic to close that topic’s door
against unsigned deliveries.
A verifier is bound per hook topic. The binding names the environment variable that
holds the signing secret through config.secret_env — the verifier looks that
variable up at verify time, so the secret itself never lives in the manifest:
GitHub sends no signed timestamp, so replay is defended by remembering each delivery’s
X-GitHub-Delivery id in a seen-set. config takes an optional replay_window_seconds
(a positive int, default 86400 — one day) setting how long an id is remembered:
A delivery whose id was already seen within that window is refused as a replay. A manual
redelivery of the same event carries the same id and is the correct idempotent no-op.
Fails closed. A missing secret_env key, a missing environment variable, an
empty secret, a missing X-GitHub-Delivery header, or a non-positive / non-int
replay_window_seconds raises loudly rather than degrading to an unauthenticated
door. A malformed or mismatched signature is an ordinary verification failure.
Replay-deduped. Each delivery’s X-GitHub-Delivery id is remembered in a
seen-set for replay_window_seconds (default one day); a replay within the window is
refused and nothing re-dispatches.
POST only. The signature covers the raw body, so a door binding this verifier
rejects GET.
The comparison is constant-time, and the sha256= digest must be exactly 64 hex
characters.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"TAI42","description":"tai is an open-source runtime for MCP tools, agents, and workflows — the server that hosts tools, agents, extensions, connectors, hooks, and storage for the TAI42 ecosystem.","colors":{"primary":"#DC143C","light":"#F4718A","dark":"#A01030"},"logo":{"light":"https://mintcdn.com/tai42/8zNeABFQpXRG0k_n/logo/light.png?fit=max\u0026auto=format\u0026n=8zNeABFQpXRG0k_n\u0026q=85\u0026s=2140f77615492c689d62fcb3a5df2d31","dark":"https://mintcdn.com/tai42/8zNeABFQpXRG0k_n/logo/dark.png?fit=max\u0026auto=format\u0026n=8zNeABFQpXRG0k_n\u0026q=85\u0026s=22db5fbcb0ff42b44dd8057f0edbb842"},"favicon":{"light":"https://mintcdn.com/tai42/8zNeABFQpXRG0k_n/logo/icon.png?fit=max\u0026auto=format\u0026n=8zNeABFQpXRG0k_n\u0026q=85\u0026s=93b0ca22f7b4a2c0a6a18f49aedbfd73","dark":"https://mintcdn.com/tai42/6-OGKPd0gfVyDs4N/logo/icon-dark.png?fit=max\u0026auto=format\u0026n=6-OGKPd0gfVyDs4N\u0026q=85\u0026s=e1630da05506747fe41cf300761cf3cf"},"appearance":{"default":"light"},"navbar":{"links":[{"icon":"github","href":"https://github.com/tai42ai/tai42","label":"GitHub"}],"primary":{"type":"button","label":"Get started","href":"/getting-started/installation"}},"footer":{"socials":{"github":"https://github.com/tai42ai","website":"https://tai42.ai"},"links":[{"header":"Project","items":[{"label":"Contributing","href":"/contributing"}]}]},"search":{"prompt":"Search the TAI42 docs"},"seo":{"metatags":{"og:title":"TAI42 — the OS for AI tools","og:description":"An open-source runtime for MCP tools, agents, and workflows.","og:image":"/images/og-image.svg","og:type":"website","twitter:card":"summary_large_image","twitter:title":"TAI42 — the OS for AI tools","twitter:image":"/images/og-image.svg"},"indexing":"navigable"},"fonts":{"heading":{"family":"Geist"},"body":{"family":"Inter"}},"contextual":{"options":["copy","view","chatgpt","claude"],"display":"header"},"styling":{"latex":true},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"tai42","hasAudioNarration":false,"actualSubdomain":"tai42","customDomains":["docs.tai42.ai"],"gitSource":{"type":"github","owner":"tai42ai","repo":"tai-docs","deployBranch":"main","contentDirectory":"","isPrivate":false,"mountPath":"","label":""},"chroma":{"collectionId":"70c7974a-74c7-4ee5-8636-97a098b8bbe6","liveDeploymentHistoryId":"6aeca718754501e0c6b68d06","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6aeca718754501e0c6b68d06"},"entitlements":{"AI_CHAT":{"status":"DISABLED"}},"buildId":"6aecafc07e5e99a1eb7058ad","clientVersion":"0.0.4071","searchFilterCounts":[{"language":"default","tag":"Reference","count":356},{"language":"default","tag":"HTTP API","count":260},{"language":"default","tag":"Docs","count":124},{"language":"default","tag":"CLI","count":46},{"language":"default","tag":"Python SDK","count":38},{"language":"default","tag":"Concepts","count":35},{"language":"default","tag":"access-control","count":35},{"language":"default","tag":"states","count":33},{"language":"default","tag":"Plugins","count":30},{"language":"default","tag":"conversations","count":22}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":true},"customCss":[],"page":{"pagePath":"plugins/tai42/webhook-verifier-github","slug":"/plugins/tai42/webhook-verifier-github","pageMetadata":{"title":"webhook-verifier-github","description":"GitHub webhook-signature verifier plugin for the TAI ecosystem: a per-provider WebhookVerifier that checks each delivery's X-Hub-Signature-256 HMAC before the payload is dispatched.","href":"/plugins/tai42/webhook-verifier-github"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"GitHub webhook-signature verifier plugin for the TAI ecosystem: a per-provider WebhookVerifier that checks each delivery’s X-Hub-Signature-256 HMAC before the payload is dispatched.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,Heading,Info,Table}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Info)_missingMdxReference(`Info`,true);if(!Table)_missingMdxReference(`Table`,true);return _jsxs(_Fragment,{children:[_jsxs(Info,{children:[_jsx(_components.code,{children:`Webhook verifier`}),` plugin · listing `,_jsx(_components.code,{children:`tai42/webhook-verifier-github`})]}),`\n`,_jsx(Heading,{level:`2`,id:`install`,children:`Install`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`tai`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` plugins`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` install`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` tai42-webhook-verifier-github`})]}),`\n`]})})}),`\n`,_jsx(Heading,{level:`2`,id:`permissions`,children:`Permissions`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Capability`}),_jsx(_components.th,{children:`Declared`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Network`}),_jsx(_components.td,{children:`no`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Subprocess`}),_jsx(_components.td,{children:`no`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Filesystem`}),_jsx(_components.td,{children:`no`})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`provides`,children:`Provides`}),`\n`,_jsx(Heading,{level:`3`,id:`github`,children:`github`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`Webhook verifier`}),` — Verify a GitHub webhook delivery’s X-Hub-Signature-256 HMAC before dispatch.`]}),`\n`,_jsxs(_components.p,{children:[`Registers the `,_jsx(_components.code,{children:`github`}),` webhook verifier. It authenticates an inbound delivery’s\n`,_jsx(_components.code,{children:`X-Hub-Signature-256`}),` HMAC-SHA256, computed over the exact raw request body and keyed\nby the webhook’s shared secret. Bind it to a hook topic to close that topic’s door\nagainst unsigned deliveries.`]}),`\n`,_jsx(Heading,{level:`2`,id:`bind-it-to-a-topic`,children:`Bind it to a topic`}),`\n`,_jsxs(_components.p,{children:[`A verifier is bound per hook topic. The binding names the environment variable that\nholds the signing secret through `,_jsx(_components.code,{children:`config.secret_env`}),` — the verifier looks that\nvariable up at verify time, so the secret itself never lives in the manifest:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`2`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`curl`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -X`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` PUT`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` .../api/hooks/topics/{topic}/verifier`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -d`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` '{\"verifier\": \"github\", \"config\": {\"secret_env\": \"GITHUB_WEBHOOK_SECRET\"}}'`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`Set the same secret you configured on the GitHub webhook in that variable on every\nprocess that receives deliveries:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`GITHUB_WEBHOOK_SECRET`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`...`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`The variable name is yours to choose — pick a distinct name per topic when one\ndeployment verifies several GitHub webhooks with different secrets.`}),`\n`,_jsx(Heading,{level:`3`,id:`replay-window`,children:`Replay window`}),`\n`,_jsxs(_components.p,{children:[`GitHub sends no signed timestamp, so replay is defended by remembering each delivery’s\n`,_jsx(_components.code,{children:`X-GitHub-Delivery`}),` id in a seen-set. `,_jsx(_components.code,{children:`config`}),` takes an optional `,_jsx(_components.code,{children:`replay_window_seconds`}),`\n(a positive int, default `,_jsx(_components.code,{children:`86400`}),` — one day) setting how long an id is remembered:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`json`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`json`,children:_jsxs(_components.code,{language:`json`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`{`}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"verifier\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"github\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"config\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"secret_env\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"GITHUB_WEBHOOK_SECRET\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"replay_window_seconds\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`86400`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}}`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`A delivery whose id was already seen within that window is refused as a replay. A manual\nredelivery of the same event carries the same id and is the correct idempotent no-op.`}),`\n`,_jsx(Heading,{level:`2`,id:`behaviour`,children:`Behaviour`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Fails closed.`}),` A missing `,_jsx(_components.code,{children:`secret_env`}),` key, a missing environment variable, an\nempty secret, a missing `,_jsx(_components.code,{children:`X-GitHub-Delivery`}),` header, or a non-positive / non-int\n`,_jsx(_components.code,{children:`replay_window_seconds`}),` raises loudly rather than degrading to an unauthenticated\ndoor. A malformed or mismatched signature is an ordinary verification failure.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Replay-deduped.`}),` Each delivery’s `,_jsx(_components.code,{children:`X-GitHub-Delivery`}),` id is remembered in a\nseen-set for `,_jsx(_components.code,{children:`replay_window_seconds`}),` (default one day); a replay within the window is\nrefused and nothing re-dispatches.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`POST only.`}),` The signature covers the raw body, so a door binding this verifier\nrejects GET.`]}),`\n`,_jsxs(_components.li,{children:[`The comparison is constant-time, and the `,_jsx(_components.code,{children:`sha256=`}),` digest must be exactly 64 hex\ncharacters.`]}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`see-also`,children:`See also`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`/concepts/triggers-and-webhooks`,children:`Triggers and webhooks`}),` — the verifier model and the built-in `,_jsx(_components.code,{children:`shared_secret`}),` verifier.`]}),`\n`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"webhook-verifier-github","description":"GitHub webhook-signature verifier plugin for the TAI ecosystem: a per-provider WebhookVerifier that checks each delivery's X-Hub-Signature-256 HMAC before the payload is dispatched.","href":"/plugins/tai42/webhook-verifier-github"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Install","slug":"install","depth":2,"children":[]},{"title":"Permissions","slug":"permissions","depth":2,"children":[]},{"title":"Provides","slug":"provides","depth":2,"children":[{"title":"github","slug":"github","depth":3,"children":[]}]},{"title":"Bind it to a topic","slug":"bind-it-to-a-topic","depth":2,"children":[{"title":"Replay window","slug":"replay-window","depth":3,"children":[]}]},{"title":"Behaviour","slug":"behaviour","depth":2,"children":[]},{"title":"See also","slug":"see-also","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"tai42","siteName":"TAI42","title":"TAI42 — the OS for AI tools","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-08-23T03:14:50.644Z","originalFileLocation":"plugins/tai42/webhook-verifier-github.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"light\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"GitHub webhook-signature verifier plugin for the TAI ecosystem: a per-provider WebhookVerifier that checks each delivery\u0026#x27;s X-Hub-Signature-256 HMAC before the payload is dispatched.\">\u003cmeta data-mint-head name=\"application-name\" content=\"TAI42\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"TAI42 — the OS for AI tools\">\u003cmeta data-mint-head property=\"og:description\" content=\"An open-source runtime for MCP tools, agents, and workflows.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"TAI42\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.tai42.ai/plugins/tai42/webhook-verifier-github\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://tai42.mintlify.app/images/og-image.svg\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"TAI42 — the OS for AI tools\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"An open-source runtime for MCP tools, agents, and workflows.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://tai42.mintlify.app/images/og-image.svg\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"TAI42\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#DC143C\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.tai42.ai/plugins/tai42/webhook-verifier-github\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/plugins/tai42/webhook-verifier-github.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.tai42.ai/#organization\",\"name\":\"TAI42\",\"url\":\"https://docs.tai42.ai\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/tai42/8zNeABFQpXRG0k_n/logo/light.png?fit=max\u0026auto=format\u0026n=8zNeABFQpXRG0k_n\u0026q=85\u0026s=2140f77615492c689d62fcb3a5df2d31\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.tai42.ai#website\",\"name\":\"TAI42\",\"url\":\"https://docs.tai42.ai\",\"publisher\":{\"@id\":\"https://docs.tai42.ai/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.tai42.ai/plugins/tai42/webhook-verifier-github#webpage\",\"url\":\"https://docs.tai42.ai/plugins/tai42/webhook-verifier-github\",\"name\":\"webhook-verifier-github\",\"description\":\"GitHub webhook-signature verifier plugin for the TAI ecosystem: a per-provider WebhookVerifier that checks each delivery's X-Hub-Signature-256 HMAC before the payload is dispatched.\",\"dateModified\":\"2026-08-23T03:14:50.644Z\",\"isPartOf\":{\"@id\":\"https://docs.tai42.ai#website\"},\"breadcrumb\":{\"@id\":\"https://docs.tai42.ai/plugins/tai42/webhook-verifier-github#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.tai42.ai/plugins/tai42/webhook-verifier-github#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Plugins\",\"item\":\"https://docs.tai42.ai/plugins/index\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"webhook-verifier-github\",\"item\":\"https://docs.tai42.ai/plugins/tai42/webhook-verifier-github\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.tai42.ai/plugins/tai42/webhook-verifier-github#article\",\"headline\":\"webhook-verifier-github\",\"name\":\"webhook-verifier-github\",\"description\":\"GitHub webhook-signature verifier plugin for the TAI ecosystem: a per-provider WebhookVerifier that checks each delivery's X-Hub-Signature-256 HMAC before the payload is dispatched.\",\"url\":\"https://docs.tai42.ai/plugins/tai42/webhook-verifier-github\",\"mainEntityOfPage\":{\"@id\":\"https://docs.tai42.ai/plugins/tai42/webhook-verifier-github#webpage\"},\"image\":\"https://docs.tai42.ai/images/og-image.svg\",\"dateModified\":\"2026-08-23T03:14:50.644Z\",\"publisher\":{\"@id\":\"https://docs.tai42.ai/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.tai42.ai#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"TAI42\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"TAI42","nav":{"global":null,"tabs":[{"tab":"Docs","groups":[{"group":"Get started","icon":"rocket","pages":[{"title":"TAI42 — the OS for AI tools","sidebarTitle":"Welcome","icon":"house","mode":"wide","href":""},{"title":"Installation","icon":"download","href":"/getting-started/installation"},{"title":"Quickstart","icon":"rocket","href":"/getting-started/quickstart"},{"title":"Mental model","icon":"brain","href":"/getting-started/mental-model"}]},{"group":"Concepts","icon":"lightbulb","pages":[{"title":"Concepts","icon":"compass","href":"/concepts/index"},{"group":"Foundations","icon":"sitemap","pages":[{"title":"The layering","icon":"sitemap","href":"/concepts/layering"},{"title":"The manifest","icon":"scroll","href":"/concepts/manifest"},{"title":"Tools and extensions","icon":"wrench","href":"/concepts/tools-and-extensions"},{"title":"Presets","icon":"layer-group","href":"/concepts/presets"},{"title":"Tool organization","icon":"folder-tree","href":"/concepts/tool-organization"}]},{"group":"Agents","icon":"robot","pages":[{"title":"Agents","icon":"robot","href":"/concepts/agents"},{"title":"Deep agents","icon":"diagram-project","href":"/concepts/deep-agents"},{"title":"Classifiers","icon":"scale-balanced","href":"/concepts/classifiers"},{"title":"Client conversations","icon":"comments","href":"/concepts/client-conversations"}]},{"group":"Around the tool","icon":"wrench","pages":[{"title":"Interactions","icon":"comments","href":"/concepts/interactions"},{"title":"Asking the caller","icon":"reply","href":"/concepts/asking-the-caller"},{"title":"Notifications","icon":"bell","href":"/concepts/notifications"},{"title":"Connectors","icon":"plug","href":"/concepts/connectors"},{"title":"Hooks","icon":"anchor","href":"/concepts/hooks"},{"title":"Triggers and webhook verifiers","icon":"bolt","href":"/concepts/triggers-and-webhooks"},{"title":"Storage and resources","icon":"database","href":"/concepts/storage-and-resources"},{"title":"Backends","icon":"server","href":"/concepts/backends"},{"title":"Sandbox","icon":"box","href":"/concepts/sandbox"}]},{"group":"Platform surfaces","icon":"shield-halved","pages":[{"title":"Access control","icon":"shield-halved","href":"/concepts/access-control"},{"title":"Accounts","icon":"user-lock","href":"/concepts/accounts"},{"title":"Member actions","icon":"user-gear","href":"/concepts/member-actions"},{"title":"User types and permissions","icon":"user-shield","href":"/concepts/permissions"},{"title":"Owned keys","icon":"share-nodes","href":"/concepts/owned-keys"},{"title":"Config and secrets","icon":"key","href":"/concepts/config-and-secrets"},{"title":"Secret values","icon":"user-secret","href":"/concepts/secret-values"},{"title":"Transports","icon":"network-wired","href":"/concepts/transports"},{"title":"Private tool sets","icon":"box","href":"/concepts/private-tool-sets"},{"title":"The MCP-citizen surface","icon":"diagram-project","href":"/concepts/mcp-citizen-surface"},{"title":"The versioning spine","icon":"code-branch","href":"/concepts/versioning-spine"},{"title":"Live operations","icon":"gauge-high","href":"/concepts/live-operations"},{"title":"The worker bus","icon":"tower-broadcast","href":"/concepts/worker-bus"},{"title":"States","icon":"database","href":"/concepts/states"},{"title":"jq variables","icon":"dollar-sign","href":"/concepts/jq-variables"},{"title":"The marketplace","icon":"store","href":"/concepts/marketplace"}]}]},{"group":"Guides","icon":"map","pages":[{"title":"Guides","icon":"map","href":"/guides/index"},{"group":"Using the OS","icon":"wrench","pages":[{"title":"Build a tool","icon":"wrench","href":"/guides/build-a-tool"},{"title":"Bring an MCP server","icon":"plug","href":"/guides/bring-an-mcp-server"},{"title":"Connect an OAuth provider","icon":"key","href":"/guides/connect-an-oauth-provider"},{"title":"Apply an extension","icon":"puzzle-piece","href":"/guides/apply-an-extension"},{"title":"Create and version a preset","icon":"layer-group","href":"/guides/create-and-version-a-preset"},{"title":"Author an agent","icon":"robot","href":"/guides/author-an-agent"},{"title":"Use the ready-made agents","icon":"wand-magic-sparkles","href":"/guides/use-the-ready-made-agents"},{"title":"Use interactions","icon":"comments","href":"/guides/use-interactions"},{"title":"The standard toolbox","icon":"toolbox","href":"/guides/standard-toolbox"},{"title":"Set up access control","icon":"shield-halved","href":"/guides/access-control"},{"title":"Use owned keys","icon":"share-nodes","href":"/guides/owned-keys"},{"title":"Schedule a tool","icon":"clock","href":"/guides/schedule-a-tool"},{"title":"Fire a tool from a webhook","icon":"bolt","href":"/guides/fire-a-tool-from-a-webhook"},{"title":"WhatsApp to an agent","icon":"whatsapp","href":"/guides/whatsapp-to-agent"},{"title":"Telegram / Slack to an agent","icon":"hashtag","href":"/guides/telegram-slack-to-agent"},{"title":"Link a person across channels","icon":"link","href":"/guides/link-a-person-across-channels"},{"title":"Connect your own system","icon":"webhook","href":"/guides/connect-your-own-system"},{"title":"One bot, many skills","icon":"sitemap","href":"/guides/one-bot-many-skills"},{"title":"Manage stored content and templates","icon":"database","href":"/guides/manage-stored-content"},{"title":"Expose a private tool set","icon":"box","href":"/guides/private-tool-set"}]}]},{"group":"Operate","icon":"server","pages":[{"title":"Operate","icon":"server","href":"/operate/index"},{"group":"Run and operate","icon":"cloud-arrow-up","pages":[{"title":"Deploy","icon":"cloud-arrow-up","href":"/operate/deploy"},{"title":"Infrastructure by feature","icon":"layer-group","href":"/operate/infrastructure"},{"title":"Deploying the Studio","icon":"cloud-arrow-up","href":"/operate/studio"},{"title":"Embed in your own ASGI process","icon":"server","href":"/operate/embed"},{"title":"Manage a fleet","icon":"server","href":"/operate/manage-a-fleet"},{"title":"Observe","icon":"chart-line","href":"/operate/observe"},{"title":"Back up and restore","icon":"floppy-disk","href":"/operate/backup-and-restore"},{"title":"Checkpoints and retention","icon":"clock-rotate-left","href":"/operate/checkpoints"}]},{"group":"Plugin setup","icon":"puzzle-piece","pages":[{"title":"Task backends","icon":"server","href":"/operate/backends"},{"title":"Sandbox","icon":"box","href":"/operate/sandbox"},{"title":"Storage providers","icon":"database","href":"/operate/storage"},{"title":"Accounts and sign-in","icon":"user-lock","href":"/operate/accounts"}]}]},{"group":"Self-hosted","icon":"box","pages":[{"title":"Self-hosted","icon":"box","href":"/self-hosted/index"},{"title":"Quickstart","icon":"docker","href":"/self-hosted/quickstart"},{"title":"Web stacks","icon":"window","href":"/self-hosted/web-stacks"},{"title":"Upgrades","icon":"arrow-up-right-dots","href":"/self-hosted/upgrades"},{"title":"Verify artifacts","icon":"shield-check","href":"/self-hosted/verify"},{"title":"Ops notes","icon":"screwdriver-wrench","href":"/self-hosted/ops"}]},{"group":"Marketplace","icon":"store","pages":[{"title":"Marketplace","icon":"store","href":"/marketplace/index"},{"title":"Browse and search","icon":"magnifying-glass","href":"/marketplace/browse"},{"title":"Install a plugin","icon":"download","href":"/marketplace/install"},{"title":"Advisories","icon":"triangle-exclamation","href":"/marketplace/advisories"},{"title":"Author plugin docs","icon":"file-lines","href":"/marketplace/authoring-docs"},{"title":"Publish a connector without code","icon":"file-code","href":"/plugins/authoring-descriptor-plugins"}]},{"group":"Integrations","icon":"plug","pages":[{"title":"Integrations","icon":"plug","href":"/integrations/index"},{"title":"Claude Desktop","icon":"comment","href":"/integrations/claude-desktop"},{"title":"Cursor","icon":"arrow-pointer","href":"/integrations/cursor"},{"title":"MCP clients","icon":"plug","href":"/integrations/mcp-clients"}]},{"group":"Babelfish","icon":"fish","pages":[{"title":"Babelfish","icon":"fish","href":"/babelfish/index"},{"title":"Flows editor","icon":"pen-ruler","href":"/babelfish/studio"},{"title":"The agenda state template","icon":"list-checks","href":"/babelfish/agenda"},{"title":"Visual jq in flows","icon":"diagram-project","href":"/babelfish/jq-editor"},{"title":"Wiring an outcome by hand","icon":"diagram-next","href":"/babelfish/wire-form"}]},{"group":"Plugins","icon":"puzzle-piece","pages":[{"title":"Plugins","icon":"puzzle-piece","href":"/plugins/index"},{"group":"Tools","icon":"wrench","pages":[{"title":"toolbox","href":"/plugins/tai42/toolbox"},{"title":"tools-github","href":"/plugins/tai42/tools-github"},{"title":"tools-stripe","href":"/plugins/tai42/tools-stripe"},{"title":"tools-twilio","href":"/plugins/tai42/tools-twilio"},{"title":"tools-whatsapp","href":"/plugins/tai42/tools-whatsapp"}]},{"group":"Identity","icon":"id-card","pages":[{"title":"accounts-postgres","href":"/plugins/tai42/accounts-postgres"},{"title":"identity-redis","href":"/plugins/tai42/identity-redis"}]},{"group":"Agents","icon":"robot","pages":[{"title":"agents","href":"/plugins/tai42/agents"}]},{"group":"Backends","icon":"server","pages":[{"title":"backend-arq","href":"/plugins/tai42/backend-arq"},{"title":"backend-celery","href":"/plugins/tai42/backend-celery"},{"title":"backend-rq","href":"/plugins/tai42/backend-rq"}]},{"group":"Sandboxes","icon":"box","pages":[{"title":"sandbox-docker","href":"/plugins/tai42/sandbox-docker"},{"title":"sandbox-local","href":"/plugins/tai42/sandbox-local"}]},{"group":"Channels","icon":"paper-plane","pages":[{"title":"channel-slack","href":"/plugins/tai42/channel-slack"},{"title":"channel-telegram","href":"/plugins/tai42/channel-telegram"},{"title":"channel-twilio","href":"/plugins/tai42/channel-twilio"},{"title":"channel-web","href":"/plugins/tai42/channel-web"},{"title":"channel-whatsapp","href":"/plugins/tai42/channel-whatsapp"}]},{"group":"Monitoring","icon":"chart-line","pages":[{"title":"monitoring-langfuse","href":"/plugins/tai42/monitoring-langfuse"}]},{"group":"Storage","icon":"database","pages":[{"title":"storage-github","href":"/plugins/tai42/storage-github"},{"title":"storage-local","href":"/plugins/tai42/storage-local"},{"title":"storage-s3","description":"S3 storage backend for the TAI ecosystem — text, binary, and media content over an S3 bucket.","href":"/plugins/tai42/storage-s3"}]},{"group":"Webhook verifiers","icon":"bolt","pages":[{"title":"webhook-verifier-github","href":"/plugins/tai42/webhook-verifier-github"},{"title":"webhook-verifier-stripe","description":"Stripe webhook-signature verifier plugin for the TAI ecosystem: a per-provider WebhookVerifier that checks each delivery's Stripe-Signature HMAC before the payload is dispatched.","href":"/plugins/tai42/webhook-verifier-stripe"}]},{"group":"Connect outside systems","icon":"plug","pages":[{"title":"Atlassian","href":"/plugins/tai42/connector-atlassian"},{"title":"GitHub","href":"/plugins/tai42/connector-github"},{"title":"Google","href":"/plugins/tai42/connector-google"},{"title":"Slack","href":"/plugins/tai42/connector-slack"},{"title":"mcp-dynamic-postgres","href":"/plugins/tai42/mcp-dynamic-postgres"}]}]}]},{"tab":"Studio","pages":[{"title":"Studio","href":"/studio"}]},{"tab":"Reference","pages":[{"title":"Reference","href":"/reference/api"}]}]},"basePath":"","title":"TAI42 — the OS for AI tools","buildId":"dpl_GZsjphRpnhWkstV12jxWNcMHFyox","deploymentId":"dpl_GZsjphRpnhWkstV12jxWNcMHFyox","dynamics":[],"chunks":[]}