Skip to main content

GitHub Audit

Fluency collects GitHub organization webhook events — everything GitHub emits for an organization and every repository it owns. Members added, removed and promoted; repositories created, deleted and made public; branch protections and rulesets changed; deploy keys and personal access tokens requested; GitHub App installations changed; secret-scanning, code-scanning and Dependabot alerts; and the day-to-day pushes, pull requests and workflow runs those controls sit around. For an organization whose source code, CI pipelines and deployment credentials live in GitHub, that is a first-class security feed.

The mechanism is push, not poll. GitHub sends an HTTP POST to a URL as each event happens; nothing is fetched on a schedule. Authentication is a shared secret you invent: GitHub never transmits it, but uses it as the HMAC key for a SHA-256 signature it sends in the X-Hub-Signature-256 header of every delivery, which is what proves a delivery came from GitHub and was not tampered with.

The setup has two halves, and they run in the opposite order to most integrations:

  1. In Fluency — install the GitHub via Org Webhook application template with a Security Token you choose. The install produces a Webhook URL.
  2. In GitHub — create an organization webhook pointing at that URL, with that token as its Secret.
This integration installs backwards — Fluency first

On most integrations you create a credential in the vendor's console and paste it into Fluency. Here Fluency generates half of what GitHub needs: the Webhook URL does not exist until the application is installed, so the Fluency half has to come first.

Two consequences follow, and both catch people out.

A Running badge means listening, not working. Between the install and the webhook being configured on GitHub, an empty index is the expected state and proves nothing either way. The signal that the link is live is GitHub's own ping — see step 5.

The two values travel towards GitHub, not away from it. A Webhook URL and its token together are write access to your lake: anything that can POST to that URL with that signature produces records. They are far easier to leave behind in a ticket or a chat thread than a credential you fetched from a vendor. Paste them straight into GitHub's form.

An earlier version of this page sent you to the wrong place

The version of this page published between July and August 2026 said GitHub had no application template and told the reader to build a REST integration by hand on Platform → Integrations, polling the audit-log API. That was wrong: GitHub via Org Webhook (GitHubOrg) is in the Cloud-based Business Softwares category and is the supported path.

If you built an audit-log poller from that guidance it is still doing something useful — see What the audit log adds, which covers the parts of the record a webhook genuinely cannot deliver — but it is not a substitute for this template, and this template is not a substitute for it.

What arrives

StreamHow it gets hereWhat decides its contentsContents
Organization webhook deliveriesGitHub POSTs to the Webhook URL as each event happensThe event set chosen on the GitHub webhook — this guide asks for Send me everythingOne record per delivery, carrying GitHub's whole event payload

There is one feed and one destination. Unlike most templates, GitHubOrg takes no datalake or datalake index name parameter — the destination is fixed by the template rather than chosen on the form, so there is nothing here to collide with another application. To see where the data actually lands, open the installed application's details panel with the blue eye button and read its Actions list, which records every object the install created.

One record per delivery, wrapped rather than flattened

Each delivery is handled by the standard GitHub_Adjustments processor, which you can read in full at Platform → Processors. It does not flatten GitHub's payload into columns. It puts the delivery body whole under @github and stamps the record with a fixed set of fields:

FieldValue
@githubGitHub's event payload, verbatim
@typeevent
@event_typegithub
@eventTypeGitHubWebhook
@senderGitHub
@sourceWebhook
@parserfpl-GitHubWebhookAdjustments
@timestampSet when the delivery is processed

Two of those decide how you write anything against this feed.

Everything you care about is nested under @github. The actor is @github.sender.login, the repository is @github.repository.full_name, the organization is @github.organization.login, and on the events that carry one, the specific thing that happened is the payload's own top-level action@github.action. GitHub's payload shape differs per event, and the event name itself travels in a header rather than in the body, so there is no single field that names the event type across all of them; the webhook events and payloads reference is the schema.

@timestamp is arrival time, not event time. The processor stamps it at ingest. That matters more than usual here, because GitHub does not guarantee delivery order — see Ordering and duplicates below.

Which events arrive

Send me everything subscribes to every event an organization webhook can carry. Grouped by what a security team does with them:

GroupEventsWhy it matters
Membership and accessorganization, membership, member, team, team_add, org_blockWho joined, left, was promoted to owner, or was added to a team with write access.
Credentials and applicationspersonal_access_token_request, deploy_key, installation_repositories, installation_targetTokens requested against the org, keys added to repositories, GitHub Apps given more repositories.
Repository lifecycle and controlsrepository, public, fork, create, delete, repository_ruleset, branch_protection_rule, branch_protection_configuration, custom_property, custom_property_valuesA private repository made public, a repository deleted, branch protection removed before a push.
Code and CIpush, pull_request, pull_request_review, pull_request_review_comment, pull_request_review_thread, commit_comment, workflow_run, workflow_job, check_run, check_suite, deployment, deployment_status, release, package, registry_package, page_build, statusWhat changed, who approved it, and what ran as a result.
Security alertingcode_scanning_alert, secret_scanning_alert, secret_scanning_alert_location, secret_scanning_scan, dependabot_alert, repository_advisory, repository_vulnerability_alert, security_and_analysisGitHub Advanced Security findings, and the settings that turn them on and off.
Collaborationissues, issue_comment, issue_dependencies, discussion, discussion_comment, label, milestone, project, project_card, project_column, projects_v2, projects_v2_item, projects_v2_status_update, star, watch, gollumBulk of the volume on an active org; rarely the bulk of the value.
The webhook itselfping, metaping is sent once when the webhook is created. meta fires when the webhook is deleted — which makes it the one event that reports its own feed being switched off.

Four events exist for repository webhooks and are not available to an organization webhook: deployment_protection_rule, deployment_review, repository_dispatch and repository_import.

Volume lives in CI, not in security

On an organization with active pipelines, workflow_job, check_run and check_suite fire several times per run and will dominate the record count by a wide margin, with push, pull_request and issue_comment behind them. If volume has to be cut, cut there — but read step 4 first, because narrowing the subscription has a cost that is not obvious.

What does not arrive

A webhook is a notification of things that happen after it exists. Three gaps follow, and none of them is a misconfiguration to hunt for.

No history. Nothing from before the webhook was created will ever arrive through it. Configure the webhook on day one of the investigation window you care about, not on the day you start searching.

No authentication events. Enumerate the organization webhook event list above and there is nothing about a user signing in — no session, no SSO assertion, no failed password, no MFA outcome. GitHub does not publish sign-in activity as a webhook event at all, so no subscription setting and no Fluency parameter will produce it. It exists only in the audit log.

No Git operations other than push. A push event is delivered; a clone and a fetch are not. Repository exfiltration by clone — the thing most people picture when they say "GitHub audit" — is invisible to this feed. It is recorded in the audit log's git category, which is GitHub Enterprise Cloud only, reachable only through the REST API, and retained for seven days.

GitHub itself frames the two as complementary rather than as alternatives, in the note at the top of its own audit-log page:

Webhooks might be a good alternative to the audit log or API polling for certain use cases. […] Compared to the API or searching the audit log, webhooks can be more efficient if you just want to learn and possibly log when certain events occur on your enterprise, organization, or repository.

What the audit log adds sets out what a second, API-based collection would buy and what it costs.

Ordering and duplicates

GitHub documents both, so neither is a fault to raise:

GitHub may deliver webhooks in a different order than the order in which the events took place. If you need to know when the event occurred relative to another event, you should use the timestamps that are included in the delivery payload.

Because @timestamp is set at ingest, sorting on it gives you arrival order. Where the payload carries its own time — @github.head_commit.timestamp on a push, the object's created_at or updated_at on most others — that is the field to reason about sequence with.

Duplicates arrive only when somebody creates them. GitHub does not retry a failed delivery of its own accord, and a redelivery requested from Recent deliveries re-sends the original payload, so replaying a missed window will produce a second copy of anything that did arrive the first time. That is the expected cost of recovering a gap.

Before you begin

Organization owner on GitHub. GitHub's wording is "You must be an organization owner to create webhooks in that organization." Repository admin is not enough, and a repository webhook is not a substitute: it covers one repository and carries none of the organization-level events — memberships, teams, org settings — that make this feed worth collecting.

Any GitHub plan. Organization webhooks are not gated behind GitHub Enterprise Cloud. The audit-log API is, which is the main practical reason this template exists.

A publicly resolvable, HTTPS Fluency endpoint. The Webhook URL the install produces is on your Fluency instance and GitHub has to reach it from the internet. Two constraints are GitHub's, not ours: localhost and 127.0.0.1 are rejected outright, and GitHub webhooks do not support IPv6 — an endpoint published only as an AAAA record cannot be delivered to. If anything filters inbound traffic to your instance, GitHub's current delivery ranges are the hooks array of https://api.github.com/meta:

curl -s https://api.github.com/meta | jq -r '.hooks[]'

GitHub changes these occasionally, so an allow list built from them needs re-checking.

Access to the Fluency portal with permission to install applications.

A decision about the Security Token before you start. It is a template parameter, and template parameters are read-only after install — changing it later means uninstalling and reinstalling. Step 1 is the whole of that decision.

Part 1 — Fluency

1. Choose the Security Token

This is the one credential in this catalog you invent rather than fetch. GitHub's requirement for it is that you "choose a random string of text with high entropy", and its only job is to be the HMAC key: GitHub's API reference describes the field as the value that "will be used as the key to generate the HMAC hex digest value for delivery signature headers".

Generate one rather than typing one:

openssl rand -hex 32

Keep it somewhere you can paste from twice. It has to be byte-identical on both sides, and neither side has a confirmation field or shows you the value again in plain text once saved.

2. Install the application

Go to Platform → Applications → Install Application From Template and choose GitHub via Org Webhook from the Cloud-based Business Softwares category.

ParameterNotes
Security TokenThe string from step 1. It has to match the Secret you will set on the GitHub webhook exactly.

Setup New GitHub via Org Webhook Application panel showing the Template Name, Description, Name, Display Name and a single required Security Token parameter

One parameter is the whole form. There is no Advanced Configurations section, because there is no lake or index to choose, and nothing here selects which events to collect — that decision belongs entirely to the GitHub side.

Leave Name and Display Name at default / Default unless you are installing a second instance — collecting from a second GitHub organization, for example — in which case give each one a name you will recognise on the applications list. The instance name is what the pipeline objects are named after, so two instances with different names do not collide.

Press Install. The application then appears in the Installed Applications view, where its badge reads Running once the pipeline is up.

3. Collect the Webhook URL

Open the installed application's details panel with the blue eye button on its card. The panel is titled Viewing GitHubOrg Application and adds an Outputs section — the part of the panel the templates that issue a credential use, rather than consume one. It holds the Webhook URL the install created, with a copy button at the right edge of the field.

Viewing GitHubOrg Application panel showing the Security Token parameter, the Webhook URL output with a copy button, and the router, sink, pipe and data source the install created

The Actions list below it is the record of what the install built — a router, a data sink, a data source and one pipe carrying the GitHub_Adjustments processor, each named after the instance. Because nothing is polled, the source node in the card's pipeline diagram is a Webhook rather than a Plugin Data Source; it only moves when GitHub posts.

That URL and the token from step 1 are the two values GitHub needs. Everything else happens in the other tab.

Part 2 — GitHub

4. Create the organization webhook

  1. In the upper-right corner of any page on GitHub, click your profile picture, then Your organizations.

  2. To the right of the organization, click Settings.

  3. In the left sidebar, click Webhooks.

    GitHub organization settings sidebar with Webhooks highlighted under the Code, planning, and automation group

  4. Click Add webhook.

  5. Under Payload URL, paste the Webhook URL from step 3.

  6. Set Content type to application/json.

  7. Under Secret, paste the Security Token from step 1.

  8. Leave SSL verification on Enable SSL verification.

  9. Under Which events would you like to trigger this webhook?, select Send me everything.

  10. Leave Active ticked.

  11. Click Add webhook.

GitHub's Add webhook form, showing Payload URL, Content type set to application/json, Secret, SSL verification enabled, the three event-scope options and the Active checkbox above a green Add webhook button

Three of those steps are worth a sentence each.

Step 6 changes a default, and the default is the wrong one here. GitHub's own API reference gives the content type default as form. Left alone, application/x-www-form-urlencoded "will send the JSON payload as a form parameter called payload" rather than as the request body — the same data in a different envelope. Choose application/json so the delivery arrives as the JSON document the rest of this page describes.

Step 9 is deliberately the opposite of GitHub's general advice. GitHub tells integrators to "only subscribe to the webhook events that you need", which is right for an application that reacts to events and wrong for a log collector that has to answer questions nobody has asked yet. Two things make Send me everything the better default here: a webhook is not retroactive, so an event class you did not subscribe to on day one is simply gone; and Send me everything is stored as the wildcard subscription GitHub documents as "all possible events", which means event types GitHub adds later are included without anybody revisiting the webhook. An individually selected list is frozen on the day it was made. If volume forces the issue, narrow it deliberately and write down what you gave up.

Step 8 is the default and should stay that way. The Webhook URL is HTTPS; disabling certificate verification buys nothing and GitHub labels it (not recommended) on the form.

5. Check the ping

After you create a new webhook, GitHub will send you a simple ping event to let you know you've set up the webhook correctly.

That single delivery is the vendor-side proof the link is live, and it is the check that separates configured correctly and quiet from never connected.

Click the webhook in the list, then Recent deliveries. A ping should be listed with a green tick and a 2xx response. Click the delivery GUID to see the request headers, the payload GitHub sent and the response it got back.

Deliveries can take a few minutes to appear, and Recent deliveries only lists the past three days. If you need another one later, ping the webhook again from the REST API:

curl -sS -X POST \
-H "Authorization: Bearer $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
https://api.github.com/orgs/ORG/hooks/HOOK_ID/pings

A classic personal access token needs the admin:org_hook scope for that, and the caller must be an organization owner. HOOK_ID is in the webhook's URL in the browser, and GET /orgs/ORG/hooks lists them.

Confirm it is running

Three checks, in the order that narrows fastest.

1. GitHub says the delivery succeeded. Recent deliveries with a green tick and a 2xx is the only place that tells you GitHub tried and we accepted. A red icon means GitHub tried and we did not — the error string it prints is diagnostic, and the troubleshooting table is keyed on those strings. No deliveries listed at all means GitHub never fired: the webhook is inactive, or it was created on a repository rather than the organization.

2. Fluency says the application is up. The card in Installed Applications reads GitHub via Org Webhook: Default with a Running badge; Aborted in red means the pipeline stopped on an error, and the details panel carries the message. Remember that Running here only means the endpoint is listening.

3. The ping is in the lake. This is the one that proves both halves at once. The ping payload is the only GitHub delivery that carries a zen property, so @github.zen matches exactly one record — the moment the webhook was created — and no others. Every record from this integration also carries @sender of GitHub and @eventType of GitHubWebhook.

Once the ping is through, generate something ordinary and auditable — invite and remove a test member, or change a repository setting — and look for it. There is no polling interval to wait out; a webhook delivery is near-immediate, and GitHub's own advice is to wait a few minutes before concluding anything, because deliveries can take that long to appear even in its own log.

See Confirm data is arriving for the three platform-side checks — application health, ingress volume and storage-side queueing.

Silence is ambiguous, and only GitHub can resolve it

An empty result means one of three things: nothing happened in the organization, GitHub is not delivering, or we are rejecting what it delivers. Those look identical from the Fluency side and are trivially distinguished from GitHub's Recent deliveries tab. Check there first, always.

Maintenance

Nothing here expires. There is no token lifetime, no consent to renew and no certificate to rotate. What there is instead is a configuration on somebody else's console that any organization owner can switch off, and nothing that tells us when they do.

Rotating the Security Token

Template parameters are read-only after install, so changing the token means replacing the application. Done naively that leaves a gap, because the new install issues a new Webhook URL as well as taking a new token — GitHub keeps posting to an endpoint that no longer exists, and GitHub does not retry.

Install the replacement before removing the original, so the two overlap:

  1. Install GitHub via Org Webhook again with a different Namerotate-2026-09, say — and the new token. Because the template has no index parameter and names its objects after the instance, the second install does not collide with the first.
  2. Collect the new Webhook URL from its details panel.
  3. On GitHub, edit the existing webhook: replace Payload URL with the new URL and Secret with the new token, then Update webhook. Editing in place keeps the webhook's delivery history and its ID.
  4. Confirm a delivery succeeds against the new endpoint.
  5. Uninstall the original application in Fluency.

Steps 1 to 4 are a single browser session; anything delivered during them lands on one endpoint or the other.

Reviewing the webhook

Because nothing expires, maintenance here is review rather than rotation. Two things are worth putting on a calendar:

  • Is the webhook still active? Any organization owner can clear Active, edit the Payload URL, or delete the webhook outright, and nothing on our side reports it. The feed simply stops. GitHub's own audit log records all three under its hook category — readable in the web view by any organization owner, but collectable into Fluency only on Enterprise Cloud, where the audit-log API exists. Without that, the check is Recent deliveries.
  • Deleting the webhook announces itself once. The meta event fires when a webhook is deleted, and it is delivered to that webhook before it goes. A meta record in the lake is the last thing this integration will ever send — worth a detection rule of its own.

Recovering a gap

If the endpoint was unreachable for a period, GitHub has the failed deliveries and will not resend them on its own. You can replay them for three days afterwards, and no longer:

  • From the browser — the webhook's Recent deliveries tab, open a delivery, click Redeliver.
  • From the REST APIGET /orgs/ORG/hooks/HOOK_ID/deliveries lists them, with a status that is not OK on the failures, and POST /orgs/ORG/hooks/HOOK_ID/deliveries/DELIVERY_ID/attempts replays one. Both need admin:org_hook and organization ownership. GitHub publishes a worked script that runs this on a schedule.

A redelivery re-sends the original payload, so replaying a window that partly succeeded will duplicate the part that did. Beyond three days the deliveries are gone from GitHub's side; whatever the audit log covers is the only route back to them.

Removing the integration

Take the GitHub side down first, which is the reverse of the usual order and for a reason: an uninstalled application leaves a dead URL, and GitHub keeps posting to it and logging failures until somebody notices.

  1. On GitHub, open the webhook and either clear Active — which stops deliveries and keeps the configuration — or delete it.
  2. In Fluency, open the application's details panel and press the red Uninstall button.

What the audit log adds

The webhook is the live feed. GitHub's audit log is a separate record that GitHub serves on request, and it holds three things the webhook structurally cannot:

Organization webhookOrganization audit log
DeliveryPushed as events happenPulled on request
HistoryNone — starts when the webhook is createdThe last 180 days; Git events, 7 days
Sign-in and authentication activityNot published as webhook eventsPresent
Git clone and fetchNot published as webhook eventsPresent in the git category
Code, CI and review activityPresent — pushes, pull requests, reviews, workflow runsLargely absent
AvailabilityAny GitHub planThe web view on any plan; the API requires GitHub Enterprise Cloud

There is no application template for the audit-log API, so collecting it means building a connector by hand on Platform → Integrations: a credential with the read:audit_log scope held by an organization owner, an API-pull source against GET /orgs/{org}/audit-log with a polling interval, include=git if Git events are wanted, and a processor that sets the event type. See the Integration Matrix for how the two paths are recorded.

Two limitations are worth knowing before that work is scheduled. The audit-log REST API returns only the last three months unless the query names a wider window explicitly, and when it is asked for Git events it omits any change made through the browser or the APIs — merging a pull request in the web interface pushes to the base branch, and that push is not in the Git-event response.

Organizations on Enterprise Cloud have a third option that is neither of these: audit log streaming, which GitHub delivers to object storage and to several SIEM destinations on its own schedule. It is a different delivery model again, and it is not what this template does.

Troubleshooting

The error strings in the first column are GitHub's own, printed against the delivery in Recent deliveries. Start there rather than on the Fluency side: this integration's failures are almost all visible from GitHub, and almost none of them are visible from here.

SymptomLikely causeFix
Application Running, no records, no deliveries listed on GitHubGitHub never fired. The webhook is inactive, was created on a repository rather than the organization, or nothing has happened in the organization yet.Check Active on the webhook and that you are looking at the organization's Settings → Webhooks, not a repository's. Then trigger something — inviting and removing a test member does it.
Deliveries listed, but every response is a 4xxThe Secret on GitHub and the Security Token on the application are not identical, or the Payload URL is not the one the install issued.Compare both against the details panel. If the token is the suspect, rotate it — it cannot be edited in place.
timed outGitHub gives a webhook endpoint 10 seconds to return a 2xx and records anything slower as a failure.Check the platform's health. Redeliver from Recent deliveries once it is back.
failed to connect to hostGitHub could not resolve the Payload URL, or network restrictions blocked it. GitHub webhooks do not support IPv6, so an AAAA-only endpoint fails here.Confirm the host resolves to an IPv4 address from outside your network, and that GitHub's hooks ranges from https://api.github.com/meta are permitted inbound.
failed to connect to networkThe connection was refused.Same check as above.
Peer certificate cannot be authenticated with given CA certificatesThe endpoint is serving a self-signed certificate, or an incomplete chain.Test it with openssl s_client -connect HOST:443 and look for verify error. Do not answer this by disabling SSL verification on the webhook.
invalid HTTP responseThe endpoint returned a 4xx or 5xx. GitHub records anything that is not 2xx as a failure.Read the response body on the delivery detail — it is captured next to the request.
URL host localhost is not supportedThe Payload URL is localhost or 127.0.0.1.Use the Webhook URL the install produced, unchanged.
Cannot have more than 20 webhooksGitHub allows up to 20 organization webhooks per event type, and Send me everything counts against all of them.Remove a webhook that is no longer used, or forward from one endpoint to several.
Data stopped, nothing changed on our sideSomebody cleared Active, edited the Payload URL, or deleted the webhook.Check the webhook on GitHub. A meta record in the lake dates the deletion; on Enterprise Cloud, the audit log's hook category dates any of the three.
Data stopped after the application was reinstalledA reinstall issues a new Webhook URL. The old one is gone and GitHub is still posting to it.Edit the webhook's Payload URL to the new value. Next time, use the overlap procedure.
Records appear out of sequenceGitHub does not guarantee delivery order, and @timestamp is set at ingest.Sort on a timestamp inside the payload — @github.head_commit.timestamp, or the object's created_at / updated_at.
Duplicate records for the same eventSomeone redelivered a window that had partly succeeded. Redeliveries re-send the original payload.Expected. Deduplicate on the payload's own identifiers — a commit SHA, an alert number, an issue or pull request node_id.
One event class never appearsIt was not in the subscription, or it is one of the four events organization webhooks cannot carry.Check Which events would you like to trigger this webhook? on the webhook. Note that widening it is not retroactive.
Sign-ins, or repository clones, never appearThey are not webhook events.See What does not arrive and What the audit log adds.
Counts do not reconcile with GitHub's audit logThey are different feeds covering overlapping but different ground.Expected. The comparison table above says which is which.

Under the hood

Engineering reference — delivery mechanics, signature scheme, record shape and API limits

What the install builds

The GitHubOrg template creates five objects, named after the instance:

Add Router: GitHubOrg-default
Add Data Sink: GitHubOrg-default
Add Pipe to Router: GitHubOrg-default to GitHub_Adjustments
Add Data Source: GitHubOrg-default
Add Router Connection to Data Source: GitHubOrg-default to GitHubOrg-default

There is no addDatalakeIndex line, which is consistent with the template exposing no lake or index parameter. The Actions list on your own installation is the authoritative record of where its data lands.

The data source is a Webhook node rather than a plugin poller, so the pipeline is idle — grey connectors in the card's diagram — until GitHub posts.

The processor

One pipe, carrying the standard GitHub_Adjustments processor, described in the catalog as "Standard: GitHub Webhook integration event adjustments" and readable at Platform → Processors. It takes the delivery body, places it whole under @github, and stamps @type, @timestamp, @event_type, @eventType, @sender, @source, @parser and @parserVersion. @timestamp comes from the processor's own clock, not from the payload.

Delivery mechanics

MethodPOST to the Payload URL
BodyThe event payload as JSON, when Content type is application/json
Response deadline10 seconds for a 2xx; anything else is recorded as a failure
Automatic retryNone. "GitHub does not automatically redeliver failed deliveries."
Delivery logThe past 3 days, in Recent deliveries and via the REST API
OrderingNot guaranteed
Webhook limit20 organization webhooks per event type
ThrottlingGitHub may slow deliveries during a surge; affected deliveries carry a throttled_at timestamp in the API
Source addressesThe hooks array of https://api.github.com/meta192.30.252.0/22, 185.199.108.0/22, 140.82.112.0/20, 143.55.64.0/20 and two IPv6 ranges, read on 3 September 2026. IPv6 is published but not yet used for webhook delivery.

Headers on every delivery

HeaderContents
X-GitHub-EventThe event name that triggered the delivery — push, membership, ping
X-GitHub-DeliveryA GUID unique per event. A redelivery reuses the original GUID.
X-GitHub-Hook-IDThe webhook's own identifier
X-GitHub-Hook-Installation-Target-Typeorganization for this integration
X-GitHub-Hook-Installation-Target-IDThe organization's identifier
X-Hub-Signature-256sha256= followed by the HMAC-SHA256 hex digest of the request body, keyed with the Secret
X-Hub-SignatureThe SHA-1 predecessor, sent for compatibility
User-AgentAlways prefixed GitHub-Hookshot/

The signature is the whole of the authentication: the secret itself is never transmitted. GitHub omits X-Hub-Signature-256 entirely when no secret is configured, which is why leaving Secret blank turns the endpoint into an unauthenticated ingest point.

Payload shape

GitHub documents a common core across the payloads — action naming what happened on the events that have one, sender naming the GitHub user who caused it, organization because the webhook is org-scoped, and repository where the event came from one. Everything else is per-event; the webhook events and payloads reference is the schema.

The ping sent at creation is the smallest of them, and the only one with a zen:

{
"zen": "Non-blocking is better than blocking.",
"hook_id": 000000000,
"hook": {
"type": "Organization",
"id": 000000000,
"name": "web",
"active": true,
"events": ["*"],
"config": {
"content_type": "json",
"insecure_ssl": "0",
"secret": "********",
"url": "https://<your-instance>/..."
}
},
"organization": { "login": "example-org" },
"sender": { "login": "octocat" }
}

"events": ["*"] is what Send me everything stores — GitHub's API reference describes it as "all possible events", which is why the subscription does not need revisiting when GitHub adds an event type.

REST endpoints for the webhook itself

All four require organization ownership, and admin:org_hook on a classic personal access token:

GET /orgs/{org}/hooks
POST /orgs/{org}/hooks/{hook_id}/pings
GET /orgs/{org}/hooks/{hook_id}/deliveries
POST /orgs/{org}/hooks/{hook_id}/deliveries/{delivery_id}/attempts

GET /orgs/{org}/audit-log is deliberately absent from that list: it is not part of the public GitHub REST description and requires GitHub Enterprise Cloud.

References

GitHub — webhooks

GitHub — audit log

Fluency