Skip to content

GitHub Public API Limitations #890

Description

@setchy

GitHub Public API Limitations

This issue collates all of the feature gaps within the public GitHub REST API and GitHub GraphQL API

Note

See GitHub Changelog for new feature announcements
See GitHub Public Roadmap for planned upcoming features

Important

Filter issues by github-api-limitation to see full backlog

Authentication Methods

GitHub REST API - Documentation

  • List Notifications endpoint /notifications
    • Filtering capabilities
      • No query parameter to filter notifications by inbox
      • No query parameter to filter notifications by saved
      • No query parameter to filter notifications by done
    • Response schema
      • No attribute in response indicating if a notification is done, saved or in the inbox.
      • When fetching ?all=true, both read and done notifications are returned with the same response shape. There is no indicator to differentiate if the notification thread is read and not done or read and done, which causes challenges with notification hover interaction button logic.
      • Notifications of subject.type CheckSuite, RepositoryInvitation or WorkflowRun always have null
        for subject.url and subject.latest_comment_url
      • Notifications of subject.type Discussion return
        for subject.url / subject.latest_comment_url which doesn't point to the latest comment. We have had to implement a fix to find these ourselves. See refactor: remove discussions html url workaround #1583
    • Private repositories Notifications show in UI but not via this API
  • Notification
    • No endpoint to mark notification as unread (can only mark a notification as read)
    • No endpoint to find CheckSuite of WorkflowRun information by notification_id
    • No endpoint to save/unsave a notification
  • Authentication

GitHub GraphQL API - Documentation

  • No query to fetch user notifications
  • No query to find CheckSuite of WorkflowRun information by notification_id
  • No query to find Release information by release_id (only by tag)

Activity

  1. pinned this issue on Mar 17, 2024
  2. changed the title [-]GitHub API Limitiation Registry[/-] [+]GitHub Public API Limitiation Registry[/+] on Apr 3, 2024
  3. changed the title [-]GitHub Public API Limitiation Registry[/-] [+]GitHub Public API Limitation Registry[/+] on Jun 12, 2025
  4. 0xdevalias commented on Aug 21, 2025

    @0xdevalias

    While it's been a while since I was looking at it, this thread for adding support to view notifications to the gh CLI might have some pointers towards API workarounds, eg:

    • Ability to read notifications cli/cli#659 (comment)
      • IIRC you cannot mark notifications as Done, just Read

      • A little light reverse engineering seems to show that the webpage makes a call to /notifications/beta/archive when I click the button

    • Ability to read notifications cli/cli#659 (comment)
      • Seems like the Mobile app is using some graphQL API endpoints behind a feature flag

      • POST /graphql HTTP/2
        Host: api.github.com
        Content-Type: application/json
        Graphql-Features: merge_queue,private_profile_setting,project_next_field_configuration,issues_close_state,project_next_recent_connection,file_level_commenting,issue_types,sub_issues
        Accept: application/vnd.github.merge-info-preview+json,application/vnd.github.shadow-cat-preview+json,application/vnd.github.echo-preview+json,application/vnd.github.starfox-preview+json,application/vnd.github.doctor-strange-preview+json
        Apollographql-Client-Version: 1.192.0-152022212
        Authorization: Bearer REDACTED
        Accept-Encoding: gzip, deflate, br
        Accept-Language: en-GB;q=1.0, en-AU;q=0.9, ja-AU;q=0.8, fa-AU;q=0.7
        Content-Length: 4030
        User-Agent: GitHub/1.192.0 (com.github.stormbreaker.prod; build:152022212; iOS 18.2.1; iPhone15,3)
        X-Apollo-Operation-Type: query
        Apollographql-Client-Name: com.github.stormbreaker.prod-apollo-ios
        X-Apollo-Operation-Name: Inbox
        
        {
            "operationName": "Inbox",
            "query": "query Inbox($first: Int!, $after: String, $filterBy: NotificationThreadFilters, $query: String, $avatarSize: Int!) { viewer { __typename id ...WebNotificationsEnabledFragment notificationThreads( first: $first after: $after filterBy: $filterBy query: $query ) { __typename pageInfo { __typename hasNextPage endCursor } totalCount nodes { __typename ...NotificationThreadCommonFieldsFragment url subject { __typename ... on CheckSuite { ...InboxSubjectCheckSuiteFieldsFragment } ... on WorkflowRun { ...InboxSubjectWorkflowRunFieldsFragment } ... on Commit { ...InboxSubjectCommitFieldsFragment } ... on Gist { ...InboxSubjectGistFieldsFragment } ... on TeamDiscussion { ...InboxSubjectTeamDiscussionFieldsFragment } ... on Issue { ...InboxSubjectIssueFieldsFragment } ... on PullRequest { ...InboxSubjectPullRequestFieldsFragment } ... on Release { ...InboxSubjectReleaseFieldsFragment } ... on RepositoryVulnerabilityAlert { ...InboxSubjectRepositoryVulnerabilityAlertFieldsFragment } ... on RepositoryAdvisory { ...InboxSubjectRepositoryAdvisoryFieldsFragment } ...InboxSubjectDiscussionFieldsFragment ... on RepositoryDependabotAlertsThread { ...InboxSubjectRepositoryDependabotAlertsThreadFieldsFragment } ... on SecurityAdvisory { ...InboxSubjectSecurityAdvisoryFieldsFragment } } } } } }\nfragment AvatarFragment on Actor { __typename avatarUrl(size: $avatarSize) }\nfragment InboxSubjectCheckSuiteFieldsFragment on CheckSuite { __typename id url conclusion status }\nfragment InboxSubjectCommitFieldsFragment on Commit { __typename id abbreviatedOid url repository { __typename id owner { __typename id login } name } }\nfragment InboxSubjectDiscussionFieldsFragment on Discussion { __typename id url number discussionStateReason: stateReason answer { __typename id } category { __typename id isAnswerable } repository { __typename id isOrganizationDiscussionRepository } }\nfragment InboxSubjectGistFieldsFragment on Gist { __typename url id }\nfragment InboxSubjectIssueFieldsFragment on Issue { __typename id number issueState: state stateReason issueHtmlTitle: titleHTML url }\nfragment InboxSubjectPullRequestFieldsFragment on PullRequest { __typename id number pullRequestHtmlTitle: titleHTML url ...PullRequestStateIcon }\nfragment InboxSubjectReleaseFieldsFragment on Release { __typename id tagName url }\nfragment InboxSubjectRepositoryAdvisoryFieldsFragment on RepositoryAdvisory { __typename id url }\nfragment InboxSubjectRepositoryDependabotAlertsThreadFieldsFragment on RepositoryDependabotAlertsThread { __typename id notificationsPermalink }\nfragment InboxSubjectRepositoryVulnerabilityAlertFieldsFragment on RepositoryVulnerabilityAlert { __typename id permalink }\nfragment InboxSubjectSecurityAdvisoryFieldsFragment on SecurityAdvisory { __typename id ghsaId notificationsPermalink }\nfragment InboxSubjectTeamDiscussionFieldsFragment on TeamDiscussion { __typename url id }\nfragment InboxSubjectWorkflowRunFieldsFragment on WorkflowRun { __typename id url runNumber workflow { __typename id name } checkSuite { __typename id } }\nfragment ListSubscribableFragment on Subscribable { __typename id viewerSubscription viewerCanSubscribe }\nfragment NotificationThreadCommonFieldsFragment on NotificationThread { __typename id threadType title isUnread unreadItemsCount lastUpdatedAt subscriptionStatus summaryItemAuthor { __typename id ...AvatarFragment } summaryItemBody isArchived isSaved reason list { __typename ...ListSubscribableFragment ... on Repository { id owner { __typename id login } name } ... on User { id login userName: name } ... on Team { id organization { __typename id login } slug } ... on Organization { id login } } }\nfragment PullRequestStateIcon on PullRequest { __typename pullRequestState: state isDraft mergeQueueEntry { __typename id position } }\nfragment WebNotificationsEnabledFragment on User { __typename notificationSettings { __typename getsParticipatingWeb getsWatchingWeb } }",
            "variables":
            {
                "avatarSize": 48,
                "first": 30,
                "query": ""
            }
        }
      • And then if I click on a filter tab in the iOS app like 'unread' it changes query to is:unread; saved is is:saved, done is is:done, etc
      • Mark notification as 'undone':
        • POST /graphql HTTP/1.1
          Host: api.github.com
          GraphQL-Features: merge_queue,private_profile_setting,project_next_field_configuration,issues_close_state,project_next_recent_connection,file_level_commenting,issue_types,sub_issues
          Authorization: Bearer gho_REDACTED
          Accept: multipart/mixed;deferSpec=20220824,application/graphql-response+json,application/json,application/vnd.github.merge-info-preview+json,application/vnd.github.shadow-cat-preview+json,application/vnd.github.echo-preview+json,application/vnd.github.starfox-preview+json,application/vnd.github.doctor-strange-preview+json
          apollographql-client-version: 1.222.0-170680083
          Accept-Language: en-GB;q=1.0, en-AU;q=0.9, ja-AU;q=0.8, fa-AU;q=0.7
          Accept-Encoding: br;q=1.0, gzip;q=0.9, deflate;q=0.8
          Content-Type: application/json
          Content-Length: 265
          User-Agent: GitHub/1.222.0 (com.github.stormbreaker.prod; build:170680083; iOS 18.6.0; iPhone15,3)
          X-APOLLO-OPERATION-TYPE: mutation
          apollographql-client-name: com.github.stormbreaker.prod-apollo-ios
          Connection: keep-alive
          X-APOLLO-OPERATION-NAME: MarkNotificationAsUndone
          
          {
            "operationName": "MarkNotificationAsUndone",
            "query": "mutation MarkNotificationAsUndone($notificationId: ID!) { markNotificationAsUndone(input: { id: $notificationId }) { __typename success } }",
            "variables": {
              "notificationId": "NT_kwDOAAuA47E4ODcxMjU0MzkzOjc1Mzg5MQ"
            }
          }
      • Save/unsave/view saved: feature: save/saved notifications #840 (comment)

    Some of the private APIs used on https://github.com/notifications (though likely less useful as they use authenticity_token to prevent CSRF:

    • mark as read:
      • POST https://github.com/notifications/beta/mark
      • MIME Type: multipart/form-data
      • ------WebKitFormBoundaryLqH0emMzDeIcrXrh
        Content-Disposition: form-data; name="authenticity_token"
        
        REDACTED
        ------WebKitFormBoundaryLqH0emMzDeIcrXrh
        Content-Disposition: form-data; name="notification_ids[]"
        
        NT_kwDOAAuA47IxODEzREDACTED
        ------WebKitFormBoundaryLqH0emMzDeIcrXrh
        Content-Disposition: form-data; name="notification_ids[]"
        
        NT_kwDOAAuA47IxODM0REDACTED
        ------WebKitFormBoundaryLqH0emMzDeIcrXrh--
        
    • mark as unread:
      • POST https://github.com/notifications/beta/unmark
      • MIME Type: multipart/form-data
      • ------WebKitFormBoundaryBWyAgv8M6HPBkTAX
        Content-Disposition: form-data; name="authenticity_token"
        
        REDACTED
        ------WebKitFormBoundaryBWyAgv8M6HPBkTAX
        Content-Disposition: form-data; name="notification_ids[]"
        
        NT_kwDOAAuA47IxODEzREDACTED
        ------WebKitFormBoundaryBWyAgv8M6HPBkTAX
        Content-Disposition: form-data; name="notification_ids[]"
        
        NT_kwDOAAuA47IxODM0REDACTED
        ------WebKitFormBoundaryBWyAgv8M6HPBkTAX--
        
    • mark as done / archive:
      • POST https://github.com/notifications/beta/archive
      • MIME Type: multipart/form-data
      • ------WebKitFormBoundary1RpEegHaXAmtMNxM
        Content-Disposition: form-data; name="authenticity_token"
        
        REDACTED
        ------WebKitFormBoundary1RpEegHaXAmtMNxM
        Content-Disposition: form-data; name="notification_ids[]"
        
        NT_kwDOAAuA47IxODEzREDACTED
        ------WebKitFormBoundary1RpEegHaXAmtMNxM
        Content-Disposition: form-data; name="notification_ids[]"
        
        NT_kwDOAAuA47IxODM0REDACTED
        ------WebKitFormBoundary1RpEegHaXAmtMNxM--
        
  5. changed the title [-]GitHub Public API Limitation Registry[/-] [+]GitHub Public API Limitations[/+] on Nov 1, 2025
  6. removed
    documentationImprovements or additions to documentation
    on Mar 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    forge:githubGitHub Cloud, GitHub Enterprise

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions