# GitHub Issues Event

> GitHub issues webhook payload with labels, milestones, assignees, and state tracking.

- Name: `github-issues-event`
- Categories: github
- Depends on: `@open-types/github-shared`
- Detail page: https://open-types.dev/types/github-issues-event

## Install

```bash
# Types only
npx shadcn add @open-types/github-issues-event

# Types + Zod v4 validators
npx shadcn add @open-types/github-issues-event-zod

# Types + real-world examples
npx shadcn add @open-types/github-issues-event-examples
```

## Types

```typescript
import type {
  GitHubUser,
  GitHubRepository,
  GitHubOrganization,
  GitHubLabel,
  GitHubMilestone,
} from "./github-shared";

export type GitHubIssuesAction =
  | "assigned"
  | "closed"
  | "deleted"
  | "demilestoned"
  | "edited"
  | "labeled"
  | "locked"
  | "milestoned"
  | "opened"
  | "pinned"
  | "reopened"
  | "transferred"
  | "unassigned"
  | "unlabeled"
  | "unlocked"
  | "unpinned";

export interface GitHubIssue {
  id: number;
  node_id: string;
  number: number;
  title: string;
  user: GitHubUser;
  labels: GitHubLabel[];
  state: "open" | "closed";
  locked: boolean;
  assignees: GitHubUser[];
  milestone: GitHubMilestone | null;
  comments: number;
  created_at: string;
  updated_at: string;
  closed_at: string | null;
  body: string | null;
  state_reason?: string | null;
  html_url: string;
  url: string;
}

export interface GitHubIssuesChanges {
  title?: { from: string };
  body?: { from: string };
}

export interface GitHubIssuesEvent {
  action: GitHubIssuesAction;
  issue: GitHubIssue;
  repository: GitHubRepository;
  sender: GitHubUser;
  organization?: GitHubOrganization;
  label?: GitHubLabel;
  assignee?: GitHubUser;
  milestone?: GitHubMilestone;
  changes?: GitHubIssuesChanges;
}
```

## Zod validator

```typescript
import * as z from "zod";
import type {
  GitHubIssuesAction,
  GitHubIssue,
  GitHubIssuesChanges,
  GitHubIssuesEvent,
} from "../types/github-issues-event";
import {
  githubUserSchema,
  githubRepositorySchema,
  githubOrganizationSchema,
  githubLabelSchema,
  githubMilestoneSchema,
} from "./github-shared";

export const githubIssuesActionSchema = z.enum([
  "assigned",
  "closed",
  "deleted",
  "demilestoned",
  "edited",
  "labeled",
  "locked",
  "milestoned",
  "opened",
  "pinned",
  "reopened",
  "transferred",
  "unassigned",
  "unlabeled",
  "unlocked",
  "unpinned",
]);

export const githubIssueSchema = z.object({
  id: z.number().int(),
  node_id: z.string(),
  number: z.number().int(),
  title: z.string(),
  user: githubUserSchema,
  labels: z.array(githubLabelSchema),
  state: z.enum(["open", "closed"]),
  locked: z.boolean(),
  assignees: z.array(githubUserSchema),
  milestone: githubMilestoneSchema.nullable(),
  comments: z.number().int(),
  created_at: z.string(),
  updated_at: z.string(),
  closed_at: z.string().nullable(),
  body: z.string().nullable(),
  state_reason: z.string().nullable().optional(),
  html_url: z.string(),
  url: z.string(),
}) satisfies z.ZodType<GitHubIssue>;

export const githubIssuesChangesSchema = z.object({
  title: z.object({ from: z.string() }).optional(),
  body: z.object({ from: z.string() }).optional(),
}) satisfies z.ZodType<GitHubIssuesChanges>;

export const githubIssuesEventSchema = z.object({
  action: githubIssuesActionSchema,
  issue: githubIssueSchema,
  repository: githubRepositorySchema,
  sender: githubUserSchema,
  organization: githubOrganizationSchema.optional(),
  label: githubLabelSchema.optional(),
  assignee: githubUserSchema.optional(),
  milestone: githubMilestoneSchema.optional(),
  changes: githubIssuesChangesSchema.optional(),
}) satisfies z.ZodType<GitHubIssuesEvent>;

export type {
  GitHubIssuesAction,
  GitHubIssue,
  GitHubIssuesChanges,
  GitHubIssuesEvent,
} from "../types/github-issues-event";
```

## Examples

```typescript
// Source: https://docs.github.com/en/webhooks/webhook-events-and-payloads#issues
// Captured: 2026-05
import type {
  GitHubIssue,
  GitHubIssuesChanges,
  GitHubIssuesEvent,
} from "../types/github-issues-event";
import {
  githubUserOctocat,
  githubUserBot,
  githubRepositoryHelloWorld,
  githubOrganizationGitHub,
  githubLabelBug,
  githubMilestoneV1,
} from "./shared/github.examples";

const issueMinimal = {
  id: 1,
  node_id: "MDU6SXNzdWUx",
  number: 1347,
  title: "Found a bug",
  user: githubUserOctocat,
  labels: [],
  state: "open",
  locked: false,
  assignees: [],
  milestone: null,
  comments: 0,
  created_at: "2024-09-10T13:45:00Z",
  updated_at: "2024-09-12T10:30:00Z",
  closed_at: null,
  body: "I'm having a problem with this.",
  html_url: "https://github.com/octocat/Hello-World/issues/1347",
  url: "https://api.github.com/repos/octocat/Hello-World/issues/1347",
} as const satisfies GitHubIssue;

const issueFull = {
  ...issueMinimal,
  labels: [githubLabelBug],
  assignees: [githubUserOctocat],
  milestone: githubMilestoneV1,
  comments: 3,
  state_reason: null,
} as const satisfies GitHubIssue;

const issueClosed = {
  ...issueFull,
  state: "closed",
  closed_at: "2024-09-12T11:00:00Z",
  state_reason: "completed",
} as const satisfies GitHubIssue;

export const githubIssueExamples = {
  minimal: issueMinimal,
  full: issueFull,
  closed: issueClosed,
  notPlanned: { ...issueClosed, state_reason: "not_planned" } satisfies GitHubIssue,
  emptyBody: { ...issueMinimal, body: null } satisfies GitHubIssue,
  locked: { ...issueMinimal, locked: true } satisfies GitHubIssue,
} as const;

export const githubIssuesChangesExamples = {
  title: { title: { from: "Bug" } } satisfies GitHubIssuesChanges,
  body: { body: { from: "Original body" } } satisfies GitHubIssuesChanges,
  both: {
    title: { from: "Old title" },
    body: { from: "Old body" },
  } satisfies GitHubIssuesChanges,
  empty: {} satisfies GitHubIssuesChanges,
} as const;

const opened = {
  action: "opened",
  issue: issueMinimal,
  repository: githubRepositoryHelloWorld,
  sender: githubUserOctocat,
} as const satisfies GitHubIssuesEvent;

export const githubIssuesEventExamples = {
  opened,
  closed: {
    ...opened,
    action: "closed",
    issue: issueClosed,
  } satisfies GitHubIssuesEvent,
  reopened: { ...opened, action: "reopened" } satisfies GitHubIssuesEvent,
  labeled: {
    ...opened,
    action: "labeled",
    issue: { ...issueMinimal, labels: [githubLabelBug] },
    label: githubLabelBug,
  } satisfies GitHubIssuesEvent,
  assigned: {
    ...opened,
    action: "assigned",
    issue: { ...issueMinimal, assignees: [githubUserOctocat] },
    assignee: githubUserOctocat,
  } satisfies GitHubIssuesEvent,
  milestoned: {
    ...opened,
    action: "milestoned",
    issue: { ...issueMinimal, milestone: githubMilestoneV1 },
    milestone: githubMilestoneV1,
  } satisfies GitHubIssuesEvent,
  edited: {
    ...opened,
    action: "edited",
    changes: { title: { from: "Original title" } },
  } satisfies GitHubIssuesEvent,
  openedByBot: {
    ...opened,
    issue: { ...issueMinimal, user: githubUserBot },
    sender: githubUserBot,
  } satisfies GitHubIssuesEvent,
  withinOrg: { ...opened, organization: githubOrganizationGitHub } satisfies GitHubIssuesEvent,
} as const;
```
