diff --git a/package.json b/package.json
index e0f23311b..fcd46f155 100644
--- a/package.json
+++ b/package.json
@@ -139,6 +139,7 @@
     "@biomejs/biome": "1.9.4",
     "@discordapp/twemoji": "15.1.0",
     "@electron/notarize": "2.5.0",
+    "@octokit/openapi-types": "22.2.0",
     "@primer/octicons-react": "19.12.0",
     "@testing-library/react": "16.0.1",
     "@types/jest": "29.5.14",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 15223f80d..e77f494f5 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -42,6 +42,9 @@ importers:
       '@electron/notarize':
         specifier: 2.5.0
         version: 2.5.0
+      '@octokit/openapi-types':
+        specifier: 22.2.0
+        version: 22.2.0
       '@primer/octicons-react':
         specifier: 19.12.0
         version: 19.12.0(react@18.3.1)
@@ -601,6 +604,9 @@ packages:
     engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
     deprecated: This functionality has been moved to @npmcli/fs
 
+  '@octokit/openapi-types@22.2.0':
+    resolution: {integrity: sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==}
+
   '@pkgjs/parseargs@0.11.0':
     resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
     engines: {node: '>=14'}
@@ -4648,6 +4654,8 @@ snapshots:
       mkdirp: 1.0.4
       rimraf: 3.0.2
 
+  '@octokit/openapi-types@22.2.0': {}
+
   '@pkgjs/parseargs@0.11.0':
     optional: true
 
diff --git a/src/renderer/components/RepositoryNotifications.tsx b/src/renderer/components/RepositoryNotifications.tsx
index f48d64377..d536cfd86 100644
--- a/src/renderer/components/RepositoryNotifications.tsx
+++ b/src/renderer/components/RepositoryNotifications.tsx
@@ -1,14 +1,14 @@
 import { CheckIcon, MarkGithubIcon, ReadIcon } from '@primer/octicons-react';
 import { type FC, type MouseEvent, useContext, useState } from 'react';
 import { AppContext } from '../context/App';
-import { Opacity, Size } from '../types';
+import { type Link, Opacity, Size } from '../types';
 import type { Notification } from '../typesGitHub';
 import { cn } from '../utils/cn';
+import { openExternalLink } from '../utils/comms';
 import {
   getChevronDetails,
   isMarkAsDoneFeatureSupported,
 } from '../utils/helpers';
-import { openRepository } from '../utils/links';
 import { HoverGroup } from './HoverGroup';
 import { NotificationRow } from './NotificationRow';
 import { InteractionButton } from './buttons/InteractionButton';
@@ -67,7 +67,9 @@ export const RepositoryNotifications: FC<IRepositoryNotifications> = ({
             onClick={(event: MouseEvent<HTMLElement>) => {
               // Don't trigger onClick of parent element.
               event.stopPropagation();
-              openRepository(repoNotifications[0].repository);
+              openExternalLink(
+                repoNotifications[0].repository.html_url as Link,
+              );
             }}
           >
             {repoName}
diff --git a/src/renderer/components/notification/NotificationHeader.tsx b/src/renderer/components/notification/NotificationHeader.tsx
index a4c9dd1ff..88fc1a6dc 100644
--- a/src/renderer/components/notification/NotificationHeader.tsx
+++ b/src/renderer/components/notification/NotificationHeader.tsx
@@ -1,10 +1,10 @@
 import { MarkGithubIcon } from '@primer/octicons-react';
 import { type FC, type MouseEvent, useContext } from 'react';
 import { AppContext } from '../../context/App';
-import { Opacity, Size } from '../../types';
+import { type Link, Opacity, Size } from '../../types';
 import type { Notification } from '../../typesGitHub';
 import { cn } from '../../utils/cn';
-import { openRepository } from '../../utils/links';
+import { openExternalLink } from '../../utils/comms';
 import { AvatarIcon } from '../icons/AvatarIcon';
 
 interface INotificationHeader {
@@ -43,7 +43,7 @@ export const NotificationHeader: FC<INotificationHeader> = ({
           onClick={(event: MouseEvent<HTMLElement>) => {
             // Don't trigger onClick of parent element.
             event.stopPropagation();
-            openRepository(notification.repository);
+            openExternalLink(notification.repository.html_url as Link);
           }}
         >
           {repoSlug}
diff --git a/src/renderer/typesGitHub.ts b/src/renderer/typesGitHub.ts
index 5d6486051..017ec9aa2 100644
--- a/src/renderer/typesGitHub.ts
+++ b/src/renderer/typesGitHub.ts
@@ -1,3 +1,4 @@
+import type { components } from '@octokit/openapi-types';
 import type { Account, Link } from './types';
 
 export type Reason =
@@ -17,15 +18,6 @@ export type Reason =
   | 'subscribed'
   | 'team_mention';
 
-// Note: ANSWERED and OPEN are not an official discussion state type in the GitHub API
-export type DiscussionStateType =
-  | 'ANSWERED'
-  | 'DUPLICATE'
-  | 'OPEN'
-  | 'OUTDATED'
-  | 'REOPENED'
-  | 'RESOLVED';
-
 export type SubjectType =
   | 'CheckSuite'
   | 'Commit'
@@ -62,21 +54,6 @@ export type StateType =
   | IssueStateReasonType
   | PullRequestStateType;
 
-export type CheckSuiteStatus =
-  | 'action_required'
-  | 'cancelled'
-  | 'completed'
-  | 'failure'
-  | 'in_progress'
-  | 'pending'
-  | 'queued'
-  | 'requested'
-  | 'skipped'
-  | 'stale'
-  | 'success'
-  | 'timed_out'
-  | 'waiting';
-
 export type PullRequestReviewState =
   | 'APPROVED'
   | 'CHANGES_REQUESTED'
@@ -84,175 +61,15 @@ export type PullRequestReviewState =
   | 'DISMISSED'
   | 'PENDING';
 
-export type PullRequestReviewAuthorAssociation =
-  | 'COLLABORATOR'
-  | 'CONTRIBUTOR'
-  | 'FIRST_TIMER'
-  | 'FIRST_TIME_CONTRIBUTOR'
-  | 'MANNEQUIN'
-  | 'MEMBER'
-  | 'NONE'
-  | 'OWNER';
-
-// TODO: Add explicit types for GitHub API response vs Gitify Notifications object
-export type Notification = GitHubNotification & GitifyNotification;
-
-export interface GitHubNotification {
-  id: string;
-  unread: boolean;
-  reason: Reason;
-  updated_at: string;
-  last_read_at: string | null;
-  subject: Subject;
-  repository: Repository;
-  url: Link;
-  subscription_url: Link;
-}
-
-// Note: This is not in the official GitHub API. We add this to make notification interactions easier.
-export interface GitifyNotification {
-  account: Account;
-}
+export type GitHubNotification = components['schemas']['thread'];
 
 export type UserDetails = User & UserProfile;
 
-export interface UserProfile {
-  name: string;
-  company: string;
-  blog: string;
-  location: string;
-  email: string;
-  hireable: string;
-  bio: string;
-  twitter_username: string;
-  public_repos: number;
-  public_gists: number;
-  followers: number;
-  following: number;
-  created_at: string;
-  updated_at: string;
-  private_gists: number;
-  total_private_repos: number;
-  owned_private_repos: number;
-  disk_usage: number;
-  collaborators: number;
-  two_factor_authentication: boolean;
-  plan: Plan;
-}
-
-export interface Plan {
-  name: string;
-  space: number;
-  private_repos: number;
-  collaborators: number;
-}
-
-export interface User {
-  login: string;
-  id: number;
-  node_id: string;
-  avatar_url: Link;
-  gravatar_url: Link;
-  url: Link;
-  html_url: Link;
-  followers_url: Link;
-  following_url: Link;
-  gists_url: Link;
-  starred_url: Link;
-  subscriptions_url: Link;
-  organizations_url: Link;
-  repos_url: Link;
-  events_url: Link;
-  received_events_url: Link;
-  type: UserType;
-  site_admin: boolean;
-}
-
-export interface SubjectUser {
-  login: string;
-  html_url: Link;
-  avatar_url: Link;
-  type: UserType;
-}
-
-export interface DiscussionAuthor {
-  login: string;
-  url: Link;
-  avatar_url: Link;
-  type: UserType;
-}
-
-export interface Repository {
-  id: number;
-  node_id: string;
-  name: string;
-  full_name: string;
-  private: boolean;
-  owner: Owner;
-  html_url: Link;
-  description: string;
-  fork: boolean;
-  url: Link;
-  forks_url: Link;
-  keys_url: Link;
-  collaborators_url: Link;
-  teams_url: Link;
-  hooks_url: Link;
-  issue_events_url: Link;
-  events_url: Link;
-  assignees_url: Link;
-  branches_url: Link;
-  tags_url: Link;
-  blobs_url: Link;
-  git_tags_url: Link;
-  git_refs_url: Link;
-  trees_url: Link;
-  statuses_url: Link;
-  languages_url: Link;
-  stargazers_url: Link;
-  contributors_url: Link;
-  subscribers_url: Link;
-  subscription_url: Link;
-  commits_url: Link;
-  git_commits_url: Link;
-  comments_url: Link;
-  issue_comment_url: Link;
-  contents_url: Link;
-  compare_url: Link;
-  merges_url: Link;
-  archive_url: Link;
-  downloads_url: Link;
-  issues_url: Link;
-  pulls_url: Link;
-  milestones_url: Link;
-  notifications_url: Link;
-  labels_url: Link;
-  releases_url: Link;
-  deployments_url: Link;
-}
+export type User = components['schemas']['simple-user'];
 
-export interface Owner {
-  login: string;
-  id: number;
-  node_id: string;
-  avatar_url: Link;
-  gravatar_id: string;
-  url: Link;
-  html_url: Link;
-  followers_url: Link;
-  following_url: Link;
-  gists_url: Link;
-  starred_url: Link;
-  subscriptions_url: Link;
-  organizations_url: Link;
-  repos_url: Link;
-  events_url: Link;
-  received_events_url: Link;
-  type: string;
-  site_admin: boolean;
-}
+export type UserProfile = components['schemas']['public-user'];
 
-export type Subject = GitHubSubject & GitifySubject;
+export type Repository = components['schemas']['repository'];
 
 interface GitHubSubject {
   title: string;
@@ -261,181 +78,15 @@ interface GitHubSubject {
   type: SubjectType;
 }
 
-// This is not in the GitHub API, but we add it to the type to make it easier to work with
-export interface GitifySubject {
-  number?: number;
-  state?: StateType;
-  user?: SubjectUser;
-  reviews?: GitifyPullRequestReview[];
-  linkedIssues?: string[];
-  comments?: number;
-  labels?: string[];
-  milestone?: Milestone;
-}
-
-export interface PullRequest {
-  url: Link;
-  id: number;
-  node_id: string;
-  html_url: Link;
-  diff_url: Link;
-  patch_url: Link;
-  issue_url: Link;
-  number: number;
-  state: PullRequestStateType;
-  locked: boolean;
-  title: string;
-  user: User;
-  body: string;
-  created_at: string;
-  updated_at: string;
-  closed_at: string | null;
-  merged_at: string | null;
-  merge_commit_sha: string | null;
-  labels: Labels[];
-  milestone: Milestone | null;
-  draft: boolean;
-  commits_url: Link;
-  review_comments_url: Link;
-  review_comment_url: Link;
-  comments_url: Link;
-  statuses_url: Link;
-  author_association: string;
-  merged: boolean;
-  mergeable: boolean;
-  rebaseable: boolean;
-  comments: number;
-  review_comments: number;
-  maintainer_can_modify: boolean;
-  commits: number;
-  additions: number;
-  deletions: number;
-  changed_files: number;
-}
-
-export interface GitifyPullRequestReview {
-  state: PullRequestReviewState;
-  users: string[];
-}
-
-export interface Labels {
-  id: number;
-  node_id: string;
-  url: Link;
-  name: string;
-  color: string;
-  default: boolean;
-  description: string;
-}
-
-export interface PullRequestReview {
-  id: number;
-  node_id: string;
-  user: User;
-  body: string;
-  state: PullRequestReviewState;
-  html_url: Link;
-  pull_request_url: Link;
-  author_association: PullRequestReviewAuthorAssociation;
-  submitted_at: string;
-  commit_id: string;
-}
-
-export interface Commit {
-  sha: string;
-  node_id: string;
-  commit: {
-    author: CommitUser;
-    committer: CommitUser;
-    message: string;
-    tree: {
-      sha: string;
-      url: Link;
-    };
-    url: Link;
-    comment_count: number;
-    verification: {
-      verified: boolean;
-      reason: string;
-      signature: string | null;
-      payload: string | null;
-    };
-  };
-  url: Link;
-  html_url: Link;
-  comments_url: Link;
-  author: User;
-  committer: User;
-  parents: CommitParent[];
-  stats: {
-    total: number;
-    additions: number;
-    deletions: number;
-  };
-  files: CommitFiles[];
-}
-
-interface CommitUser {
-  name: string;
-  email: string;
-  date: string;
-}
+export type PullRequest = components['schemas']['pull-request'];
 
-interface CommitParent {
-  sha: string;
-  url: Link;
-  html_url: Link;
-}
+export type PullRequestReview = components['schemas']['pull-request-review'];
 
-interface CommitFiles {
-  sha: string;
-  filename: string;
-  status: string;
-  additions: number;
-  deletions: number;
-  changes: number;
-  blob_url: Link;
-  raw_url: Link;
-  contents_url: Link;
-  patch: string;
-}
+export type Commit = components['schemas']['commit'];
 
-export interface CommitComment {
-  url: Link;
-  html_url: Link;
-  issue_url: Link;
-  id: number;
-  node_id: string;
-  user: User;
-  created_at: string;
-  updated_at: string;
-  body: string;
-}
+export type CommitComment = components['schemas']['commit-comment'];
 
-export interface Issue {
-  url: Link;
-  repository_url: Link;
-  labels_url: Link;
-  comments_url: Link;
-  events_url: Link;
-  html_url: Link;
-  id: number;
-  node_id: string;
-  number: number;
-  title: string;
-  user: User;
-  state: IssueStateType;
-  locked: boolean;
-  labels: Labels[];
-  milestone: Milestone | null;
-  comments: number;
-  created_at: string;
-  updated_at: string;
-  closed_at: string | null;
-  author_association: string;
-  body: string;
-  state_reason: IssueStateReasonType | null;
-}
+export type Issue = components['schemas']['issue'];
 
 export interface IssueOrPullRequestComment {
   url: Link;
@@ -449,45 +100,21 @@ export interface IssueOrPullRequestComment {
   body: string;
 }
 
-export interface Milestone {
-  url: Link;
-  html_url: Link;
-  labels_url: Link;
-  id: number;
-  node_id: string;
-  number: number;
-  title: string;
-  description: string;
-  creator: User;
-  open_issues: number;
-  closed_issues: number;
-  state: MilestoneStateType;
-  created_at: string;
-  updated_at: string;
-  due_on: string | null;
-  closed_at: string | null;
-}
+export type Milestone = components['schemas']['milestone'];
 
-type MilestoneStateType = 'open' | 'closed';
+export type Release = components['schemas']['release'];
 
-export interface Release {
-  url: Link;
-  assets_url: Link;
-  upload_url: Link;
-  html_url: Link;
-  id: number;
-  author: User;
-  node_id: string;
-  tag_name: string;
-  target_commitish: string;
-  name: string | null;
-  body: string | null;
-  draft: boolean;
-  prerelease: boolean;
-  created_at: string;
-  published_at: string | null;
+export interface GitHubRESTError {
+  message: string;
+  documentation_url: Link;
 }
 
+export type NotificationThreadSubscription =
+  components['schemas']['thread-subscription'];
+
+/**
+ * GitHub GraphQL API Types
+ */
 export interface GraphQLSearch<T> {
   data: {
     search: {
@@ -507,6 +134,22 @@ export interface Discussion {
   labels: DiscussionLabels | null;
 }
 
+// Note: ANSWERED and OPEN are not an official discussion state type in the GitHub API
+export type DiscussionStateType =
+  | 'ANSWERED'
+  | 'DUPLICATE'
+  | 'OPEN'
+  | 'OUTDATED'
+  | 'REOPENED'
+  | 'RESOLVED';
+
+export interface DiscussionAuthor {
+  login: string;
+  url: Link;
+  avatar_url: Link;
+  type: UserType;
+}
+
 export interface DiscussionLabels {
   nodes: DiscussionLabel[];
 }
@@ -529,6 +172,46 @@ export interface DiscussionComment {
   };
 }
 
+/**
+ * Gitify Type Extensions
+ */
+
+// TODO: Add explicit types for GitHub API response vs Gitify Notifications object
+export type Notification = GitHubNotification & GitifyNotification;
+
+// Note: This is not in the official GitHub API. We add this to make notification interactions easier.
+export interface GitifyNotification {
+  account: Account;
+  reason: Reason;
+  subject: Subject;
+}
+
+// This is not in the GitHub API, but we add it to the type to make it easier to work with
+export type Subject = GitHubSubject & GitifySubject;
+
+export interface GitifySubject {
+  number?: number;
+  state?: StateType;
+  user?: SubjectUser;
+  reviews?: GitifyPullRequestReview[];
+  linkedIssues?: string[];
+  comments?: number;
+  labels?: string[];
+  milestone?: Milestone;
+}
+
+export interface SubjectUser {
+  login: string;
+  html_url: Link;
+  avatar_url: Link;
+  type: UserType;
+}
+
+export interface GitifyPullRequestReview {
+  state: PullRequestReviewState;
+  users: string[];
+}
+
 export interface CheckSuiteAttributes {
   workflowName: string;
   attemptNumber?: number;
@@ -543,16 +226,17 @@ export interface WorkflowRunAttributes {
   status: CheckSuiteStatus | null;
 }
 
-export interface GitHubRESTError {
-  message: string;
-  documentation_url: Link;
-}
-
-export interface NotificationThreadSubscription {
-  subscribed: boolean;
-  ignored: boolean;
-  reason: string | null;
-  created_at: string;
-  url: Link;
-  thread_url: Link;
-}
+export type CheckSuiteStatus =
+  | 'action_required'
+  | 'cancelled'
+  | 'completed'
+  | 'failure'
+  | 'in_progress'
+  | 'pending'
+  | 'queued'
+  | 'requested'
+  | 'skipped'
+  | 'stale'
+  | 'success'
+  | 'timed_out'
+  | 'waiting';
diff --git a/src/renderer/utils/api/__mocks__/response-mocks.ts b/src/renderer/utils/api/__mocks__/response-mocks.ts
index 714635ab5..002f2b05d 100644
--- a/src/renderer/utils/api/__mocks__/response-mocks.ts
+++ b/src/renderer/utils/api/__mocks__/response-mocks.ts
@@ -19,7 +19,7 @@ export const mockNotificationUser: User = {
   id: 123456789,
   node_id: 'MDQ6VXNlcjE=',
   avatar_url: 'https://avatars.githubusercontent.com/u/583231?v=4' as Link,
-  gravatar_url: '' as Link,
+  gravatar_id: '',
   url: 'https://api.github.com/users/octocat' as Link,
   html_url: 'https://github.com/octocat' as Link,
   followers_url: 'https://api.github.com/users/octocat/followers' as Link,
diff --git a/src/renderer/utils/auth/utils.ts b/src/renderer/utils/auth/utils.ts
index d79fcbce0..d762d9dbe 100644
--- a/src/renderer/utils/auth/utils.ts
+++ b/src/renderer/utils/auth/utils.ts
@@ -100,7 +100,7 @@ export async function getUserData(
     id: response.id,
     login: response.login,
     name: response.name,
-    avatar: response.avatar_url,
+    avatar: response.avatar_url as Link,
   };
 }
 
@@ -162,7 +162,7 @@ export async function refreshAccount(account: Account): Promise<Account> {
       id: res.data.id,
       login: res.data.login,
       name: res.data.name,
-      avatar: res.data.avatar_url,
+      avatar: res.data.avatar_url as Link,
     };
 
     // Refresh platform version
diff --git a/src/renderer/utils/links.test.ts b/src/renderer/utils/links.test.ts
index 7ec918363..6f86b9bc3 100644
--- a/src/renderer/utils/links.test.ts
+++ b/src/renderer/utils/links.test.ts
@@ -1,7 +1,6 @@
 import { partialMockUser } from '../__mocks__/partial-mocks';
 import { mockGitHubCloudAccount } from '../__mocks__/state-mocks';
 import type { Hostname, Link } from '../types';
-import type { Repository } from '../typesGitHub';
 import { mockSingleNotification } from './api/__mocks__/response-mocks';
 import * as authUtils from './auth/utils';
 import * as comms from './comms';
@@ -17,7 +16,6 @@ import {
   openGitifyReleaseNotes,
   openHost,
   openNotification,
-  openRepository,
   openUserProfile,
 } from './links';
 
@@ -88,19 +86,9 @@ describe('renderer/utils/links.ts', () => {
     expect(openExternalLinkMock).toHaveBeenCalledWith(mockSettingsURL);
   });
 
-  it('openRepository', () => {
-    const mockHtmlUrl = 'https://github.com/gitify-app/gitify';
-
-    const repo = {
-      html_url: mockHtmlUrl,
-    } as Repository;
-
-    openRepository(repo);
-    expect(openExternalLinkMock).toHaveBeenCalledWith(mockHtmlUrl);
-  });
-
   it('openNotification', async () => {
-    const mockNotificationUrl = mockSingleNotification.repository.html_url;
+    const mockNotificationUrl = mockSingleNotification.repository
+      .html_url as Link;
     jest
       .spyOn(helpers, 'generateGitHubWebUrl')
       .mockResolvedValue(mockNotificationUrl);
diff --git a/src/renderer/utils/links.ts b/src/renderer/utils/links.ts
index 3ea299d4b..a31975678 100644
--- a/src/renderer/utils/links.ts
+++ b/src/renderer/utils/links.ts
@@ -1,5 +1,5 @@
 import type { Account, Hostname, Link } from '../types';
-import type { Notification, Repository, SubjectUser } from '../typesGitHub';
+import type { Notification, SubjectUser } from '../typesGitHub';
 import { getDeveloperSettingsURL } from './auth/utils';
 import { openExternalLink } from './comms';
 import { Constants } from './constants';
@@ -48,10 +48,6 @@ export function openDeveloperSettings(account: Account) {
   openExternalLink(url);
 }
 
-export function openRepository(repository: Repository) {
-  openExternalLink(repository.html_url);
-}
-
 export async function openNotification(notification: Notification) {
   const url = await generateGitHubWebUrl(notification);
   openExternalLink(url);
diff --git a/src/renderer/utils/subject.ts b/src/renderer/utils/subject.ts
index 08d65abcf..e7646cbc2 100644
--- a/src/renderer/utils/subject.ts
+++ b/src/renderer/utils/subject.ts
@@ -10,9 +10,12 @@ import type {
   Notification,
   PullRequest,
   PullRequestReview,
+  PullRequestReviewState,
   PullRequestStateType,
+  StateType,
   SubjectUser,
   User,
+  UserType,
   WorkflowRunAttributes,
 } from '../typesGitHub';
 import {
@@ -224,7 +227,7 @@ async function getGitifySubjectForIssue(
 
   return {
     number: issue.number,
-    state: issue.state_reason ?? issue.state,
+    state: issue.state_reason ?? (issue.state as StateType),
     user: getSubjectUser([issueCommentUser, issue.user]),
     comments: issue.comments,
     labels: issue.labels?.map((label) => label.name) ?? [],
@@ -313,7 +316,7 @@ export async function getLatestReviewForReviewers(
 
     if (!reviewerFound) {
       reviewers.push({
-        state: prReview.state,
+        state: prReview.state as PullRequestReviewState,
         users: [prReview.user.login],
       });
     } else {
@@ -421,9 +424,9 @@ export function getSubjectUser(users: User[]): SubjectUser {
     if (user) {
       subjectUser = {
         login: user.login,
-        html_url: user.html_url,
-        avatar_url: user.avatar_url,
-        type: user.type,
+        html_url: user.html_url as Link,
+        avatar_url: user.avatar_url as Link,
+        type: user.type as UserType,
       };
 
       return subjectUser;