# GitHub Pull Request Event

> GitHub pull_request webhook payload with branches, labels, reviewers, and changes tracking.

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

## Install

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

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

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

## Types

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

export type GitHubPullRequestAction =
  | "assigned"
  | "auto_merge_disabled"
  | "auto_merge_enabled"
  | "closed"
  | "converted_to_draft"
  | "demilestoned"
  | "dequeued"
  | "edited"
  | "enqueued"
  | "labeled"
  | "locked"
  | "milestoned"
  | "opened"
  | "ready_for_review"
  | "reopened"
  | "review_request_removed"
  | "review_requested"
  | "synchronize"
  | "unassigned"
  | "unlabeled"
  | "unlocked";

export interface GitHubPullRequestBranch {
  label: string;
  ref: string;
  sha: string;
  user: GitHubUser;
  repo: GitHubRepository | null;
}

export interface GitHubPullRequest {
  id: number;
  node_id: string;
  number: number;
  state: "open" | "closed";
  locked: boolean;
  title: string;
  user: GitHubUser;
  body: string | null;
  created_at: string;
  updated_at: string;
  closed_at: string | null;
  merged_at: string | null;
  merge_commit_sha: string | null;
  head: GitHubPullRequestBranch;
  base: GitHubPullRequestBranch;
  draft: boolean;
  merged: boolean;
  mergeable: boolean | null;
  mergeable_state?: string;
  merged_by?: GitHubUser | null;
  comments?: number;
  review_comments?: number;
  commits?: number;
  additions?: number;
  deletions?: number;
  changed_files?: number;
  labels: GitHubLabel[];
  milestone: GitHubMilestone | null;
  assignee: GitHubUser | null;
  assignees: GitHubUser[];
  requested_reviewers: GitHubUser[];
  html_url: string;
  url: string;
}

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

export interface GitHubPullRequestEvent {
  action: GitHubPullRequestAction;
  number: number;
  pull_request: GitHubPullRequest;
  repository: GitHubRepository;
  sender: GitHubUser;
  organization?: GitHubOrganization;
  label?: GitHubLabel;
  changes?: GitHubPullRequestChanges;
}
```

## Zod validator

```typescript
import * as z from "zod";
import type {
  GitHubPullRequestAction,
  GitHubPullRequestBranch,
  GitHubPullRequest,
  GitHubPullRequestChanges,
  GitHubPullRequestEvent,
} from "../types/github-pull-request-event";
import {
  githubUserSchema,
  githubRepositorySchema,
  githubOrganizationSchema,
  githubLabelSchema,
  githubMilestoneSchema,
} from "./github-shared";

export const githubPullRequestActionSchema = z.enum([
  "assigned",
  "auto_merge_disabled",
  "auto_merge_enabled",
  "closed",
  "converted_to_draft",
  "demilestoned",
  "dequeued",
  "edited",
  "enqueued",
  "labeled",
  "locked",
  "milestoned",
  "opened",
  "ready_for_review",
  "reopened",
  "review_request_removed",
  "review_requested",
  "synchronize",
  "unassigned",
  "unlabeled",
  "unlocked",
]);

export const githubPullRequestBranchSchema = z.object({
  label: z.string(),
  ref: z.string(),
  sha: z.string(),
  user: githubUserSchema,
  repo: githubRepositorySchema.nullable(),
}) satisfies z.ZodType<GitHubPullRequestBranch>;

export const githubPullRequestSchema = z.object({
  id: z.number().int(),
  node_id: z.string(),
  number: z.number().int(),
  state: z.enum(["open", "closed"]),
  locked: z.boolean(),
  title: z.string(),
  user: githubUserSchema,
  body: z.string().nullable(),
  created_at: z.string(),
  updated_at: z.string(),
  closed_at: z.string().nullable(),
  merged_at: z.string().nullable(),
  merge_commit_sha: z.string().nullable(),
  head: githubPullRequestBranchSchema,
  base: githubPullRequestBranchSchema,
  draft: z.boolean(),
  merged: z.boolean(),
  mergeable: z.boolean().nullable(),
  mergeable_state: z.string().optional(),
  merged_by: githubUserSchema.nullable().optional(),
  comments: z.number().int().optional(),
  review_comments: z.number().int().optional(),
  commits: z.number().int().optional(),
  additions: z.number().int().optional(),
  deletions: z.number().int().optional(),
  changed_files: z.number().int().optional(),
  labels: z.array(githubLabelSchema),
  milestone: githubMilestoneSchema.nullable(),
  assignee: githubUserSchema.nullable(),
  assignees: z.array(githubUserSchema),
  requested_reviewers: z.array(githubUserSchema),
  html_url: z.string(),
  url: z.string(),
}) satisfies z.ZodType<GitHubPullRequest>;

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

export const githubPullRequestEventSchema = z.object({
  action: githubPullRequestActionSchema,
  number: z.number().int(),
  pull_request: githubPullRequestSchema,
  repository: githubRepositorySchema,
  sender: githubUserSchema,
  organization: githubOrganizationSchema.optional(),
  label: githubLabelSchema.optional(),
  changes: githubPullRequestChangesSchema.optional(),
}) satisfies z.ZodType<GitHubPullRequestEvent>;

export type {
  GitHubPullRequestAction,
  GitHubPullRequestBranch,
  GitHubPullRequest,
  GitHubPullRequestChanges,
  GitHubPullRequestEvent,
} from "../types/github-pull-request-event";
```

## Examples

```typescript
// Source: https://docs.github.com/en/webhooks/webhook-events-and-payloads#pull_request
// Captured: 2026-05
import type {
  GitHubPullRequestBranch,
  GitHubPullRequest,
  GitHubPullRequestChanges,
  GitHubPullRequestEvent,
} from "../types/github-pull-request-event";
import {
  githubUserOctocat,
  githubRepositoryHelloWorld,
  githubOrganizationGitHub,
  githubLabelBug,
  githubMilestoneV1,
} from "./shared/github.examples";

const headBranch = {
  label: "octocat:feature-branch",
  ref: "feature-branch",
  sha: "6dcb09b5b57875f334f61aebed695e2e4193db5e",
  user: githubUserOctocat,
  repo: githubRepositoryHelloWorld,
} as const satisfies GitHubPullRequestBranch;

const baseBranch = {
  label: "octocat:main",
  ref: "main",
  sha: "6113728f27ae82c7b1a177c8d03f9e96e0adf246",
  user: githubUserOctocat,
  repo: githubRepositoryHelloWorld,
} as const satisfies GitHubPullRequestBranch;

const forkHeadBranch = {
  label: "contributor:feature",
  ref: "feature",
  sha: "abc123def456abc123def456abc123def456abc1",
  user: { ...githubUserOctocat, login: "contributor", id: 42 },
  repo: null,
} as const satisfies GitHubPullRequestBranch;

export const githubPullRequestBranchExamples = {
  head: headBranch,
  base: baseBranch,
  deletedFork: forkHeadBranch,
} as const;

const pullRequestOpen = {
  id: 1,
  node_id: "MDExOlB1bGxSZXF1ZXN0MQ==",
  number: 1347,
  state: "open",
  locked: false,
  title: "Amazing new feature",
  user: githubUserOctocat,
  body: "Please pull these awesome changes in!",
  created_at: "2024-09-10T13:45:00Z",
  updated_at: "2024-09-12T10:30:00Z",
  closed_at: null,
  merged_at: null,
  merge_commit_sha: null,
  head: headBranch,
  base: baseBranch,
  draft: false,
  merged: false,
  mergeable: true,
  labels: [],
  milestone: null,
  assignee: null,
  assignees: [],
  requested_reviewers: [],
  html_url: "https://github.com/octocat/Hello-World/pull/1347",
  url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347",
} as const satisfies GitHubPullRequest;

const pullRequestFull = {
  ...pullRequestOpen,
  mergeable_state: "clean",
  merged_by: null,
  comments: 4,
  review_comments: 2,
  commits: 5,
  additions: 120,
  deletions: 14,
  changed_files: 6,
  labels: [githubLabelBug],
  milestone: githubMilestoneV1,
  assignee: githubUserOctocat,
  assignees: [githubUserOctocat],
  requested_reviewers: [githubUserOctocat],
} as const satisfies GitHubPullRequest;

const pullRequestMerged = {
  ...pullRequestFull,
  state: "closed",
  closed_at: "2024-09-12T11:00:00Z",
  merged_at: "2024-09-12T11:00:00Z",
  merge_commit_sha: "7e1f3a2c4d5e6f7081929394a5b6c7d8e9f0a1b2",
  merged: true,
  mergeable: null,
  mergeable_state: "clean",
  merged_by: githubUserOctocat,
} as const satisfies GitHubPullRequest;

const pullRequestDraft = {
  ...pullRequestOpen,
  draft: true,
  mergeable: null,
} as const satisfies GitHubPullRequest;

export const githubPullRequestExamples = {
  open: pullRequestOpen,
  full: pullRequestFull,
  merged: pullRequestMerged,
  draft: pullRequestDraft,
  fromFork: {
    ...pullRequestOpen,
    head: forkHeadBranch,
  } satisfies GitHubPullRequest,
  closedUnmerged: {
    ...pullRequestOpen,
    state: "closed",
    closed_at: "2024-09-12T11:00:00Z",
  } satisfies GitHubPullRequest,
} as const;

export const githubPullRequestChangesExamples = {
  title: { title: { from: "Original title" } } satisfies GitHubPullRequestChanges,
  body: { body: { from: "Original body" } } satisfies GitHubPullRequestChanges,
  empty: {} satisfies GitHubPullRequestChanges,
} as const;

const opened = {
  action: "opened",
  number: 1347,
  pull_request: pullRequestOpen,
  repository: githubRepositoryHelloWorld,
  sender: githubUserOctocat,
} as const satisfies GitHubPullRequestEvent;

export const githubPullRequestEventExamples = {
  opened,
  closed: {
    ...opened,
    action: "closed",
    pull_request: pullRequestMerged,
  } satisfies GitHubPullRequestEvent,
  reopened: { ...opened, action: "reopened" } satisfies GitHubPullRequestEvent,
  synchronize: { ...opened, action: "synchronize" } satisfies GitHubPullRequestEvent,
  readyForReview: {
    ...opened,
    action: "ready_for_review",
    pull_request: { ...pullRequestOpen, draft: false },
  } satisfies GitHubPullRequestEvent,
  convertedToDraft: {
    ...opened,
    action: "converted_to_draft",
    pull_request: pullRequestDraft,
  } satisfies GitHubPullRequestEvent,
  labeled: {
    ...opened,
    action: "labeled",
    pull_request: { ...pullRequestOpen, labels: [githubLabelBug] },
    label: githubLabelBug,
  } satisfies GitHubPullRequestEvent,
  edited: {
    ...opened,
    action: "edited",
    changes: { title: { from: "Original title" } },
  } satisfies GitHubPullRequestEvent,
  reviewRequested: {
    ...opened,
    action: "review_requested",
    pull_request: { ...pullRequestOpen, requested_reviewers: [githubUserOctocat] },
  } satisfies GitHubPullRequestEvent,
  withinOrg: { ...opened, organization: githubOrganizationGitHub } satisfies GitHubPullRequestEvent,
} as const;
```
