← Back to all posts
5 min readCentrali Team

Ingest Webhooks From Any Provider — GitHub as the Example

Store GitHub webhook events with signature verification in five minutes. The same pattern works for any provider.

TutorialIntegration

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.

How GitHub Webhook Signatures Work

GitHub signs every webhook delivery with HMAC-SHA256. The signature arrives in the x-hub-signature-256 header, prefixed with sha256=:

text
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.

Step 1: Write the Store Function

In the Centrali console, go to Logic > Functions and create a new function called Store GitHub Event.

Function editor with Store GitHub Event code

javascript
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.

Step 2: Create the HTTP Trigger

Go to Logic > Triggers and create a new trigger.

Trigger detail showing HTTP trigger URL and signature verification enabled

FieldValue
Namegithub-webhook
FunctionStore GitHub Event
TypeHTTP Trigger
Pathgithub

This gives you a public webhook URL:

https://api.centrali.io/data/workspace/{your-workspace}/api/v1/http-trigger/github

Configure Signature Verification

GitHub uses a simpler signature format than Stripe — no compound header, no timestamp. Toggle Validate Signature on and configure:

Signature configuration with x-hub-signature-256 header and sha256 extraction

SettingValue
Validate SignatureOn
Signing SecretYour GitHub webhook secret (you'll set this in GitHub too)
Signature Header Namex-hub-signature-256

Expand Advanced Signature Settings to see the extraction defaults:

Advanced signature settings showing sha256 algorithm, hex encoding, and extraction regex

SettingValue
HMAC Algorithmsha256
Digest Encodinghex
Signature Extraction Regexsha256=(.+)
Secret Encodingraw (default)

The extraction regex sha256=(.+) strips the sha256= prefix from GitHub's header value, leaving just the HMAC digest for verification.

Step 3: Configure the Webhook in GitHub

Open your repository on GitHub. Go to Settings > Webhooks > Add webhook.

GitHub webhook settings page with Centrali URL and JSON content type

FieldValue
Payload URLYour Centrali HTTP trigger URL
Content typeapplication/json
SecretThe same secret you entered in the Centrali trigger
EventsChoose which events to receive

Click Add webhook. GitHub sends a ping event immediately to verify the endpoint is reachable.

Step 4: See Your Data

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.

Collection view showing stored GitHub events with eventType, sender, and repo columns

Click into any record to see the flattened fields and the full raw payload:

Record detail showing push event with sender, repo, and raw JSON payload

Toggle JSON editor to see the complete payload GitHub delivered:

JSON editor view showing the full GitHub webhook payload

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:

GitHub recent deliveries showing successful 202 response from Centrali

The Pattern Works for Any Provider

The function + trigger pattern is the same regardless of the provider. The only things that change are:

ProviderSignature HeaderExtraction RegexSecret Format
Stripestripe-signaturev1=([^,]+)whsec_... (raw)
GitHubx-hub-signature-256sha256=(.+)Any string (raw)
Shopifyx-shopify-hmac-sha256(entire header)API secret (base64)
TwilioUses 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.

Query Programmatically

typescript
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', });

What's Next

Start building your own webhook pipeline

Building something with Centrali and want to share feedback about this feature?

Email feedback@centrali.io