AI News Hub Logo

AI News Hub

Ingest Webhooks From Any Provider — GitHub as the Example

DEV Community
Mary Olowu

Centrali can store webhook events from any provider that sends HTTP POST requests. The signature settings are configurable per trigger, so each provider gets its own verification rules — Stripe, GitHub, Shopify, Twilio, or anything else. This walkthrough uses GitHub as the example: one function, one trigger, signature verification, permanent storage. The same pattern works for any provider. GitHub signs every webhook delivery with HMAC-SHA256. The signature arrives in the x-hub-signature-256 header, prefixed with sha256=: x-hub-signature-256: sha256=d57c68ca6f92289e6987922ff26938930f6e66a2d161ef06abdf1859230aa23c This is different from Stripe's compound header (t=...,v1=...), which is why signature settings are per-trigger rather than a global config. Every provider has its own format. In the Centrali console, go to Logic > Functions and create a new function called Store GitHub Event. async function run() { const payload = executionParams.payload; const headers = executionParams.headers || {}; const eventType = headers['x-github-event'] || 'unknown'; const deliveryId = headers['x-github-delivery'] || null; const record = await api.createRecord('github-events', { eventType: eventType, deliveryId: deliveryId, sender: payload.sender?.login || null, action: payload.action || null, repo: payload.repository?.full_name || null, raw: payload, }); api.log({ message: 'Event stored', eventType, repo: payload.repository?.full_name, recordId: record.data.id }); return { success: true, recordId: record.data.id }; } A few things to note: executionParams.payload is the raw HTTP body GitHub sends. For HTTP triggers, this is the full POST body — no wrapping. executionParams.headers gives you the request headers. GitHub puts the event type in x-github-event and a unique delivery ID in x-github-delivery. The function flattens key fields (eventType, sender, repo, action) to the top level for easy filtering and keeps the full payload in raw. Before running this, create a schemaless collection called github-events. Schemaless mode accepts any shape — a push event looks nothing like an issues event. Tip: Want to follow along? Create a free workspace — this takes less than 5 minutes, no deployment required. Go to Logic > Triggers and create a new trigger. Field Value Name github-webhook Function Store GitHub Event Type HTTP Trigger Path github This gives you a public webhook URL: https://api.centrali.io/data/workspace/{your-workspace}/api/v1/http-trigger/github GitHub uses a simpler signature format than Stripe — no compound header, no timestamp. Toggle Validate Signature on and configure: Setting Value Validate Signature On Signing Secret Your GitHub webhook secret (you'll set this in GitHub too) Signature Header Name x-hub-signature-256 Expand Advanced Signature Settings to see the extraction defaults: Setting Value HMAC Algorithm sha256 Digest Encoding hex Signature Extraction Regex sha256=(.+) Secret Encoding raw (default) The extraction regex sha256=(.+) strips the sha256= prefix from GitHub's header value, leaving just the HMAC digest for verification. Note: GitHub doesn't include a timestamp in the signature header, so there's no replay protection timestamp to configure. If you need replay protection, you can enable it separately — Centrali will track delivery IDs and reject duplicates. Open your repository on GitHub. Go to Settings > Webhooks > Add webhook. Field Value Payload URL Your Centrali HTTP trigger URL Content type application/json Secret The same secret you entered in the Centrali trigger Events Choose which events to receive Click Add webhook. GitHub sends a ping event immediately to verify the endpoint is reachable. Push a commit, open a pull request, or create an issue — any event you subscribed to. Then open the github-events collection in the Centrali console. Click into any record to see the flattened fields and the full raw payload: Toggle JSON editor to see the complete payload GitHub delivered: You can verify the delivery on GitHub's side too. Go to your webhook settings and click Recent Deliveries — you'll see the response status and headers: Note: After your first events arrive, run Schema Discovery on the github-events collection to turn the auto-detected fields into filterable, sortable columns. The function + trigger pattern is the same regardless of the provider. The only things that change are: Provider Signature Header Extraction Regex Secret Format Stripe stripe-signature v1=([^,]+) whsec_... (raw) GitHub x-hub-signature-256 sha256=(.+) Any string (raw) Shopify x-shopify-hmac-sha256 (entire header) API secret (base64) Twilio — — Uses URL-based auth For providers that don't sign webhooks at all, just leave signature verification off. The function and collection work the same way. import { CentraliSDK } from '@centrali-io/centrali-sdk'; const client = new CentraliSDK({ workspaceId: 'your-workspace', clientId: process.env.CENTRALI_CLIENT_ID, clientSecret: process.env.CENTRALI_CLIENT_SECRET, }); // All push events const pushes = await client.queryRecords('github-events', { 'data.eventType': 'push', }); // Events from a specific repo const repoEvents = await client.queryRecords('github-events', { 'data.repo': 'your-org/your-repo', }); // Pull request events from a specific user const userPRs = await client.queryRecords('github-events', { 'data.eventType': 'pull_request', 'data.sender': 'octocat', }); Store Stripe Webhook Events and Query Them Forever — the original walkthrough, if you want to add Stripe alongside GitHub Get Alerted When a Stripe Charge Fails — add real-time alerting on top of stored events Query Stripe Webhook Events Like a Database — advanced querying patterns that work with any collection Your Webhook Data Is Schemaless — Here's How to Give It Structure — turn raw webhook JSON into typed, validated properties Start building your own webhook pipeline