All posts
githubapi

GitHub API: A Practical Guide for Full-Stack Developers

A practical guide to the GitHub API — REST and GraphQL, authentication options, webhooks, and building integrations against GitHub.

SR

Suhail Roushan

August 6, 2026

·
5 min read
·
0 views

Every "connect your GitHub account" button in a developer tool is backed by the same underlying API surface — the interesting engineering decisions are in authentication strategy and webhook handling, not the individual endpoint calls themselves.

The GitHub API exposes both a REST API and a GraphQL API for interacting with repositories, issues, pull requests, actions, and virtually every other GitHub resource programmatically. It supports several authentication models — personal access tokens, OAuth apps, and GitHub Apps — each suited to different integration scenarios, and webhooks for reacting to repository events in near real time.

Why the GitHub API Matters (and When to Skip It)

Building any tool that integrates with a team's GitHub workflow — CI status checks, automated PR comments, issue triage bots, deployment tracking — requires the API as the connection point. It's a mature, well-documented API, and the ecosystem of official SDKs (Octokit) makes common operations straightforward.

Skip a direct GitHub API integration if your need is fully covered by an existing GitHub Action or App from the marketplace — building a custom integration only pays off when you need behavior specific enough that an existing tool doesn't cover it.

Getting Started with the GitHub API

Using Octokit (the official SDK) with a personal access token:

import { Octokit } from "octokit";
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });

const { data: issues } = await octokit.rest.issues.listForRepo({
  owner: "vercel",
  repo: "next.js",
  state: "open",
  per_page: 10,
});

Creating a comment on a pull request:

await octokit.rest.issues.createComment({
  owner: "your-org",
  repo: "your-repo",
  issue_number: 42,
  body: "Automated check passed ✅",
});

A GraphQL query for more complex, nested data in a single request:

const result = await octokit.graphql(`
  query {
    repository(owner: "vercel", name: "next.js") {
      pullRequests(last: 5, states: OPEN) {
        nodes { title, author { login } }
      }
    }
  }
`);

Core GitHub API Concepts Every Developer Should Know

GitHub Apps are the recommended authentication model for integrations, not personal access tokens. Apps get their own identity, fine-grained repository permissions, and higher rate limits than a token tied to a personal account — worth using for anything beyond a personal script.

Webhooks push events to your server in near real time (a new PR opened, a push, a check run completed), avoiding the need to poll the API for changes:

app.post("/webhooks/github", (req, res) => {
  const event = req.headers["x-github-event"];
  if (event === "pull_request" && req.body.action === "opened") {
    handleNewPullRequest(req.body.pull_request);
  }
  res.sendStatus(200);
});

Rate limits differ meaningfully by authentication type — unauthenticated requests get a low limit, personal tokens get more, and GitHub Apps can get significantly higher limits (and limits that scale with installation count for some endpoints) — a real consideration when designing an integration expected to handle meaningful traffic.

GraphQL is often more efficient for nested/related data, letting you fetch exactly the fields you need across related resources in one request instead of multiple REST calls — worth reaching for when a REST-based approach would require several round trips to assemble the same data.

Common GitHub API Mistakes and How to Fix Them

Mistake 1: using a personal access token for a shared or production integration. This ties the integration's identity and permissions to one person's account, breaking if that account is disabled or the token is revoked. Fix: use a GitHub App for any integration meant to be shared or long-lived.

Mistake 2: not verifying webhook signatures. An unverified webhook endpoint could accept spoofed events from anyone who discovers the URL. Fix: verify the x-hub-signature-256 header against your webhook secret before trusting payload data.

import crypto from "crypto";

function verifyGithubSignature(payload: string, signature: string, secret: string) {
  const expected = "sha256=" + crypto.createHmac("sha256", secret).update(payload).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

Mistake 3: not handling rate limit responses gracefully, causing an integration to fail hard when limits are hit instead of backing off and retrying. Fix: check rate limit headers (x-ratelimit-remaining) and implement backoff behavior for rate-limited requests.

When Should You Use REST Instead of GraphQL for the GitHub API?

Use the REST API for simple, single-resource operations and when working with endpoints that don't have GraphQL equivalents (some administrative and webhook-related endpoints are REST-only). Use GraphQL when you need related data across multiple resources in one request, or want precise control over which fields are returned to minimize payload size.

GitHub API in Production

Use a GitHub App with the minimum necessary permissions for the integration's purpose — over-broad permissions are both a security risk and something reviewers will flag during any installation approval process. Also implement webhook signature verification and idempotent event handling, since GitHub's webhook delivery, like most webhook systems, doesn't guarantee exactly-once delivery.

Before deploying a GitHub integration broadly, verify it uses App-based auth (not a personal token) and that webhook signatures are verified — those two things determine whether the integration is safe to run against real repositories at scale.

Related posts

Written by Suhail Roushan — Full-stack developer. More posts on AI, Next.js, and building products at suhailroushan.com/blog.

Get in touch