---
description: Reference for verified GitHub webhook ingress from @flue/github.
title: GitHub Channel API | Flue
image: https://flueframework.com/docs/og4.jpg
---

# GitHub Channel API

AI-generated, awaiting review [ View as Markdown](https://flueframework.com/docs/api/github-channel/index.md) 

Import from `@flue/github`.

## `createGitHubChannel()`

```
function createGitHubChannel<E extends Env = Env>(
  options: GitHubChannelOptions<E>,
): GitHubChannel<E>;
```

Creates one stateless GitHub webhook channel. The callback is stored during construction and runs only for a verified non-ping delivery.

## `GitHubChannelOptions`

```
interface GitHubChannelOptions<E extends Env = Env> {
  webhookSecret: string;
  bodyLimit?: number;
  webhook(input: {
    c: Context<E>;
    delivery: GitHubWebhookDelivery;
  }): void | JsonValue | Response | Promise<void | JsonValue | Response>;
}
```

| Field         | Description                                     |
| ------------- | ----------------------------------------------- |
| webhookSecret | Secret configured on the GitHub webhook.        |
| bodyLimit     | Maximum request body in bytes. Default: 25 MiB. |
| webhook       | Receives every verified non-ping delivery.      |

Returning nothing produces an empty `200`. A JSON-compatible value becomes a JSON response. An ordinary Hono or Fetch `Response` passes through unchanged. A thrown callback falls through to Hono’s framework error handler.

## `GitHubChannel`

```
interface GitHubChannel<E extends Env = Env> {
  readonly routes: readonly ChannelRoute<E>[];
  conversationKey(ref: GitHubIssueRef): string;
  parseConversationKey(id: string): GitHubIssueRef;
}
```

`routes` contains one `POST /webhook` declaration used by discovered channel routing. A file named `channels/github.ts` is served at`/channels/github/webhook` relative to the `flue()` mount.

Conversation keys are canonical identifiers, not authorization capabilities. Pull requests use their issue number.

## Deliveries

Every verified non-ping delivery reaches `webhook` as a `GitHubWebhookDelivery`. The package does not normalize, rename, or enumerate a fixed set of events: the parsed event is forwarded with GitHub’s own field names and nesting.

```
type GitHubWebhookDelivery = {
  [Name in WebhookEventName]: {
    name: Name;
    payload: EventPayloadMap[Name];
    deliveryId: string;
    hookId?: string;
    installationTarget?: { id: string; type: string };
  };
}[WebhookEventName];
```

| Field              | Description                                                             |
| ------------------ | ----------------------------------------------------------------------- |
| name               | The X-GitHub-Event value. Discriminates payload.                        |
| payload            | GitHub’s parsed event, typed by @octokit/webhooks-types.                |
| deliveryId         | The X-GitHub-Delivery GUID. Manual redeliveries reuse it; dedupe on it. |
| hookId             | Header-derived hook id, when GitHub supplies one.                       |
| installationTarget | Header-derived installation target, when GitHub supplies one.           |

`name` is the discriminant. Narrowing on it narrows `payload` to the matching native event — `name: 'issues'` gives an `IssuesEvent`, `name: 'pull_request'`gives a `PullRequestEvent`, and so on. Within an event, branch on the native`payload.action`. Read fields with GitHub’s own names (`payload.repository.owner.login`, `payload.issue.number`,`payload.comment.in_reply_to_id`, `payload.installation?.id`).

Choosing which events to act on is application policy: subscribe to the minimum set in GitHub and branch in the handler. Events without an `action` (for example `push`) are forwarded like any other verified delivery.

The package re-exports the underlying types from `@octokit/webhooks-types`:

```
import type { EventPayloadMap, WebhookEvent, WebhookEventName } from '@flue/github';
```

GitHub `ping` is acknowledged internally and does not invoke `webhook`. Signatures are checked against the exact request bytes before JSON parsing. Ingress is JSON-only; form-encoded (`application/x-www-form-urlencoded`) deliveries are rejected on content type before verification. The package does not deduplicate `deliveryId`. Header-derived delivery, hook, and installation-target metadata must not be treated as an authorization capability.

## Identity

```
interface GitHubIssueRef {
  owner: string;
  repo: string;
  issueNumber: number;
}
```

## Errors

* `InvalidGitHubConversationKeyError`
* `InvalidGitHubInputError`, with structured `field`

See [GitHub setup](https://flueframework.com/docs/ecosystem/channels/github/) for composition with Octokit and application-owned tools.

## Docs Navigation

Current page: [GitHub Channel API](https://flueframework.com/docs/api/github-channel/)

### Sections

* [Guide](https://flueframework.com/docs/getting-started/quickstart/)
* [Reference](https://flueframework.com/docs/api/agent-api/)
* [CLI](https://flueframework.com/docs/cli/overview/)
* [SDK](https://flueframework.com/docs/sdk/overview/)
* [Ecosystem](https://flueframework.com/docs/ecosystem/)

### Runtime

* [ Configuration ](https://flueframework.com/docs/reference/configuration/)
* [ Errors Reference ](https://flueframework.com/docs/api/errors-reference/)
* [ Agent API ](https://flueframework.com/docs/api/agent-api/)
* [ Provider API ](https://flueframework.com/docs/api/provider-api/)
* [ Routing API ](https://flueframework.com/docs/api/routing-api/)
* [ GitHub Channel ](https://flueframework.com/docs/api/github-channel/)
* [ Stripe Channel ](https://flueframework.com/docs/api/stripe-channel/)
* [ Notion Channel ](https://flueframework.com/docs/api/notion-channel/)
* [ Resend Channel ](https://flueframework.com/docs/api/resend-channel/)
* [ Shopify Channel ](https://flueframework.com/docs/api/shopify-channel/)
* [ Intercom Channel ](https://flueframework.com/docs/api/intercom-channel/)
* [ Zendesk Channel ](https://flueframework.com/docs/api/zendesk-channel/)
* [ Salesforce Marketing Cloud Channel ](https://flueframework.com/docs/api/salesforce-marketing-cloud-channel/)
* [ Slack Channel ](https://flueframework.com/docs/api/slack-channel/)
* [ Discord Channel ](https://flueframework.com/docs/api/discord-channel/)
* [ Teams Channel ](https://flueframework.com/docs/api/teams-channel/)
* [ Google Chat Channel ](https://flueframework.com/docs/api/google-chat-channel/)
* [ Linear Channel ](https://flueframework.com/docs/api/linear-channel/)
* [ Telegram Channel ](https://flueframework.com/docs/api/telegram-channel/)
* [ WhatsApp Channel ](https://flueframework.com/docs/api/whatsapp-channel/)
* [ Twilio Channel ](https://flueframework.com/docs/api/twilio-channel/)
* [ Messenger Channel ](https://flueframework.com/docs/api/messenger-channel/)
* [ Streaming Protocol ](https://flueframework.com/docs/api/streaming-protocol/)
* [ Events Reference ](https://flueframework.com/docs/api/events-reference/)

### Advanced

* [ Sandbox Adapter API ](https://flueframework.com/docs/api/sandbox-api/)
* [ Data Persistence API ](https://flueframework.com/docs/api/data-persistence-api/)