neosourceDocs
Search docs

Receive a GitHub App webhook delivery

POST/api/github/webhooks

receiveGithubWebhook

GitHub's delivery endpoint for this deployment's App. Verifies `X-Hub-Signature-256` against the App's webhook secret over the raw request bytes, then records the delivery in the inbox keyed by `X-GitHub-Delivery`. Nothing is written unless the signature verifies: a missing, malformed, or wrong signature is `401` and leaves no row. A delivery that carries no `installation.id` is `400` — every App delivery but `ping` carries one, and it is what makes the delivery addressable even when the repository it names is not bound here. A body over 8 MiB is `413`, rejected by the body reader before it is hashed. A redelivery of a delivery id already held answers `202` exactly as a first delivery does — a successful dedupe is not a failure. A delivery about a repository this deployment has not bound is still recorded (with no local repository attached), so a manual redelivery has something to dedupe against. GitHub does **not** redeliver a failed App delivery on its own, so anything refused here is lost until it is replayed by hand. A per-IP ceiling of 3000/minute applies. It exists because the 8 MiB body is buffered before the signature can be checked, so an unauthenticated caller can make this node do work; it is set far above GitHub's real delivery rate from its handful of hook egress addresses, because a `429` here loses the delivery outright. A `ping` — GitHub's handshake for a newly configured webhook — verifies like any other delivery and then answers `204` with nothing stored: it names neither an installation nor a repository, so there is nothing to address it to, and it is the one delivery exempted from the `installation.id` requirement. The payload is stored verbatim and **not interpreted** beyond reading `installation.id` and `repository.id` to address it. 404 when this deployment has no GitHub App configured.

Authentication optional — this operation also accepts anonymous requests. When authenticating, use a bearer token.

curl

curl -X POST 'https://neosource.dev/api/github/webhooks' \
  -H 'Content-Type: application/json' \
  -d '{}'

fetch

fetch("https://neosource.dev/api/github/webhooks", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({}),
});

Request bodyrequired

application/json

string

Responses

202Delivery recorded, or already held (a redelivery)

204A `ping` handshake: verified, deliberately not stored

401Missing or invalid `X-Hub-Signature-256`. Nothing is stored.

413The body exceeded the route's 8 MiB cap.

Standard errors

Bodies documented once for the whole API — see standard errors.

  • 400Bad Request — one of: invalid_input
  • 404Not Found — one of: not_found
  • 429Rate limited — retry after the interval in the `Retry-After` header
  • 500Internal server error
  • 503Service temporarily unavailable / at capacity — retry after the `Retry-After` header
  • 504Gateway timeout — the request exceeded the server's handling budget