DEV Community

Cover image for Build a GitHub API integration for AI agents using Nango
Sapnesh Naik for Nango

Posted on • Originally published at nango.dev

Build a GitHub API integration for AI agents using Nango

This guide shows how to build a custom, customer-facing GitHub API integration that the AI agents in your product can act on, using Nango and an AI coding agent (Codex, Claude Code, Cursor, or any other).

By the end of this guide, you will have:

  • The ability for an AI agent in your product to create issues, comment on pull requests, and open PRs on a customer’s repositories, exposed as typed MCP tool calls instead of raw GitHub API parameters.
  • A GitHub auth UI in your product (Nango Connect) so your customers can connect their own GitHub account or install your GitHub App.
  • A durable sync that imports issues and pull requests from a customer’s repositories and keeps them up to date, so the agent always reasons over current data.
  • A signature-verified webhook handler that reacts to GitHub events (pushes, pull requests, issues) in real time.

Building a customer-facing GitHub API integration with Nango and an AI coding agent

Get the working example: the complete demo (frontend, backend, nango-integrations) is on GitHub at NangoHQ/github-api-integration. Clone it to run the whole thing end to end, or follow the guide below and let Codex generate the same functions in your own project.

What is a GitHub API integration?

A GitHub API integration connects your application or agent to a customer’s GitHub data (repositories, issues, pull requests, and commits) through GitHub’s REST and GraphQL APIs. It authenticates as a GitHub App or an OAuth App, reads data into your app with scheduled syncs, writes back with actions like creating issues or commenting on pull requests, and reacts to repository events through webhooks.

Example use cases: an AI agent that triages a customer’s issues and opens pull requests, an AI code-review product that comments on PRs, a project management tool that mirrors a customer’s issues, or a developer analytics dashboard.

Why is it hard to integrate the GitHub API into your app?

The GitHub REST API exposes repositories, issues, pull requests, commits, and webhooks. A production integration on top of it takes a few decisions up front, plus the infrastructure to keep them running.

The first is the auth type. For a customer-facing product, a GitHub App is usually the right call; reach for an OAuth App only when you are building a personal-developer tool that should act purely as the user.

Capability GitHub App OAuth App
Acts as A bot/installation The authorizing user
Fine-grained permissions Yes, per resource No, inherits the user's scope
Rate limit 5,000 to 12,500/hour (scales with org) 5,000/hour
Repository access Only repos granted at install Every repo the user can access
Best for Customer-facing products Personal-developer tools

See GitHub App vs. GitHub OAuth and GitHub’s own comparison for the full breakdown. The rest of the work is infrastructure:

  • The auth flow is not standard OAuth, and tokens are short-lived: GitHub App installation tokens expire after one hour. When “Expire user authorization tokens” is enabled (the default), user access tokens expire after 8 hours and refresh tokens after 6 months. A failed refresh shows up as the BAD_REFRESH_TOKEN error, usually after a rotated client secret or a revoked installation. Someone has to store, refresh, and encrypt all of this.
  • The Issues API also returns pull requests: GET /repos/{owner}/{repo}/issues returns both issues and PRs, and every pull request carries a pull_request field. Filter on it or you double-count.
  • Webhooks need signature verification: GitHub signs each delivery with the X-Hub-Signature-256 header (an HMAC-SHA256 of the raw body using your webhook secret). You verify it with a constant-time comparison before trusting the payload, and read the event type from X-GitHub-Event.
  • Pagination is header-driven: REST responses page through the Link header (rel="next", up to 100 items per page), and some data is only practical through GitHub’s GraphQL API, which has its own point budget.

Building all of this by hand takes weeks. With Nango and a coding agent like Codex, the same GitHub API integration ships in about an hour, the same workflow we used to build 200+ integrations across five APIs in 15 minutes.

Why use Nango for a GitHub API integration

Nango is the integration platform where coding agents build API integrations. An agent like Codex writes the integration as code in your repo, and Nango’s runtime runs it with managed auth, retries, and observability across 800+ APIs.

For a GitHub integration, we will use these Nango features:

  • Managed auth for GitHub Apps and OAuth: your product gets a customizable, white-label auth UI where customers install your GitHub App or authorize a GitHub OAuth app, while Nango handles installation and user tokens, refresh, encryption, and revocation behind it.
  • A function builder skill for Codex: to build your integration logic, Codex uses the Nango function builder skill. It researches the GitHub API, writes your actions and syncs from a prompt, tests them against a real GitHub connection, and iterates on real errors until its tests pass against your connection. The same skill works with Claude Code, Cursor, Gemini CLI, and other agents.
  • Integrations infrastructure for every use case:
    • Actions: one-off operations like creating an issue, commenting on a PR, or opening a pull request.
    • Syncs: scheduled functions that keep issues, PRs, and commits flowing into your app.
    • Webhooks: receive GitHub events, verified, and route them to your integration in real time.
    • MCP server: exposes your deployed actions as typed tools for the AI agents in your product.

Prerequisites

  • Sign up for Nango (the free tier is enough for development).
  • Add GitHub as an integration. Nango supports all the various GitHub auth types. In this demo, we’ll be registering a new GitHub App (the “GitHub App OAuth” type, integration ID github-app-oauth) with Nango’s callback URL https://api.nango.dev/oauth/callback.

Configuring a GitHub App OAuth integration in the Nango dashboard with App ID, client ID, client secret, and private key

  • Add a test connection: on the Nango dashboard, open the integration and select Connections > Add Test Connection, then authorize a GitHub account that owns a repository with a few issues and pull requests. While Codex builds your integration, it runs the generated code against this connection, so what ships has already worked against real data.
  • Give Codex a project to build in. Install the Nango CLI and run nango init: it creates a nango-integrations folder with the Nango framework bootstrapped. Set NANGO_SECRET_KEY_DEV (your dev API key, from Environment Settings in the dashboard) in nango-integrations/.env so it can test and deploy on your behalf.
  • Install the Nango skill. Run npx skills add NangoHQ/skills -s building-nango-functions-locally; the installer detects Codex and copies the skill to .agents/skills/, where Codex discovers it. The same skill works with Claude Code, Cursor, and other coding agents.

Tip: LLM training data on Nango is often stale. Add the Nango docs MCP server alongside the skill so Codex pulls current API references while it generates code: codex mcp add nango-docs --url "https://nango.dev/docs/mcp"

Sync a customer’s issues and pull requests into your app

A sync keeps a fresh copy of a customer’s GitHub data in your app. Here it imports the issues and pull requests from a connected repository, then refreshes on a schedule so new activity shows up without anyone clicking refresh.

You build it by prompting Codex with the Nango skill (type $ to mention a skill, or run /skills to browse):

$building-nango-functions-locally Build a Nango sync for the github-app-oauth integration that imports
the issues and pull requests from the repos a customer connects and keeps them up to date,
refreshing every hour. Integrate it with my frontend.
Enter fullscreen mode Exit fullscreen mode

Codex generating a Nango sync for GitHub issues and pull requests with the function builder skill

With the skill loaded, Codex:

  • Researches the GitHub API and the endpoints it needs.
  • Writes the sync and a typed model for your records.
  • Tests it against your real connection with nango dryrun.
  • Iterates on any errors until the sync works end to end.
// Codex generates this sync. You do not write it by hand.
export default createSync({
    description: 'Imports issues and pull requests from a connected repo and refreshes hourly.',
    frequency: 'every hour',
    autoStart: false, // starts once your app saves the repo metadata
    models: { GithubIssue },
    exec: async (nango) => {
        const { owner, repo } = await nango.getMetadata();
        for await (const issues of nango.paginate({
            endpoint: `/repos/${owner}/${repo}/issues`,
            params: { state: 'all', sort: 'updated', per_page: '100' },
        })) {
            // GET /issues returns pull requests too; the pull_request field tells them apart.
            await nango.batchSave(issues.map(toRecord), 'GithubIssue');
        }
    },
});
Enter fullscreen mode Exit fullscreen mode

nango.paginate follows GitHub’s Link header for you, so you do not hand-roll pagination. The full sync, with the record model, incremental updates keyed on issue activity, and the onWebhook handler, is in fetch-issues-and-pull-requests.ts in the demo repo.

When Codex finishes, it deploys the sync for you (approve the deploy when it asks):

nango deploy --sync fetch-issues-and-pull-requests dev
Enter fullscreen mode Exit fullscreen mode

Because the prompt said to integrate the frontend, Codex also wires Nango Connect into your app: customers install your GitHub App, pick which repositories to grant, and the sync starts on its own.

A customer connecting GitHub through Nango Connect and the sync importing their issues into the app

Your backend reads the synced records from Nango’s cache and serves them to your UI:

const { records } = await nango.listRecords({
    providerConfigKey: 'github-app-oauth',
    connectionId,
    model: 'GithubIssue',
});
Enter fullscreen mode Exit fullscreen mode

Run the issues sync on demand

Syncs run on a schedule (every hour in this example). When a customer wants fresh data immediately, give them a refresh button that triggers the sync on demand (behind the scenes, a nango.triggerSync call) instead of waiting for the next run. The refresh endpoint that triggers the sync is in backend/server.mjs in the demo repo.

Create issues and comment on pull requests from your app

An action is a one-off operation your product or an agent triggers on demand. This is the write-back direction: an AI agent files an issue from a support ticket, posts a review summary on a pull request, or opens a fix PR. Prompt Codex to build it:

$building-nango-functions-locally Add an action to the github-app-oauth integration that creates an issue
in a customer's repo from a typed title, body, and labels.
Enter fullscreen mode Exit fullscreen mode

Codex in the IDE building and verifying the create-issue action for the GitHub integration

Codex writes the action, tests it by opening a real issue in your connected test repository, and deploys it when you approve. The full action is in create-issue.ts in the demo repo.

// Codex generates this action; approve the deploy when it asks.
export default createAction({
    description: 'Create an issue in the connected repo',
    retries: 0, // creating an issue is not idempotent; a blind retry could open a duplicate
    exec: async (nango, input) => {
        const res = await nango.post({
            endpoint: `/repos/${input.owner}/${input.repo}/issues`,
            data: { title: input.title, body: input.body, labels: input.labels },
        });
        return { number: res.data.number, url: res.data.html_url };
    },
});
Enter fullscreen mode Exit fullscreen mode

On retries: 0: creating an issue is not idempotent, so re-running the whole action after an unknown failure could open the same issue twice. Rate-limited requests are safe because they wrote nothing, and Nango’s proxy retries those for you.

Deploy it the same way (Approve when Codex asks to deploy):

nango deploy --action create-issue dev
Enter fullscreen mode Exit fullscreen mode

Deployed GitHub actions in the Nango dashboard: create-issue, create-comment, create-pull-request, and more, with enable toggles

Commenting on a pull request uses the same shape. In GitHub, a pull request is also an issue, so a comment posts to /repos/{owner}/{repo}/issues/{number}/comments whether the number points at an issue or a PR. One more prompt adds an add-issue-comment action, and a third opens a pull request from a branch with POST /repos/{owner}/{repo}/pulls:

$building-nango-functions-locally Add actions to the github-app-oauth integration to comment on an issue
or PR, and to open a pull request from a head branch into a base branch.
Enter fullscreen mode Exit fullscreen mode

You can test any action from your app, or run it from the Nango dashboard with the Playground against your connection.

React to GitHub events in real time with webhooks

A scheduled sync is enough for most data, but GitHub is event-rich, and a lot of products need to react the moment a pull request opens or an issue changes. GitHub Apps deliver one webhook stream for the events you subscribe to (push, pull_request, issues, and more).

Nango receives those webhooks, verifies the X-Hub-Signature-256 signature against your webhook secret, and forwards the verified event to your integration, so you do not write HMAC code. Prompt Codex to wire it up:

$building-nango-functions-locally Subscribe the github-app-oauth integration to pull_request and issues
webhook events and update the synced records as soon as events arrive.
Enter fullscreen mode Exit fullscreen mode

Codex subscribing the GitHub integration to pull_request and issues webhook events

Keep the hourly sync running as a backstop. Webhook deliveries can be missed (a transient outage, a paused delivery), and a scheduled re-sync catches anything the event stream dropped. The combination of verified webhooks for freshness and a periodic sync for completeness is the pattern most production GitHub integrations settle on.

One manual step is needed to start receiving events: point your GitHub App at Nango’s webhook URL. Copy it from your integration’s settings page in the Nango dashboard, then paste it into your GitHub App under Developer settings > GitHub Apps > your app > Webhook URL.

Copying the webhook URL from the Nango integration settings into the GitHub App's webhook configuration

Give AI agents in your product access to GitHub

This is where the previous steps pay off: the sync gives the agent current GitHub data to reason over, and the actions become the tools it acts with. Once they are deployed, the AI agents inside your product can use them. Nango exposes enabled actions as typed tool calls through a hosted MCP server, so an agent calls create-issue or add-issue-comment with typed inputs instead of guessing raw GitHub API parameters.

Point your MCP client at Nango’s server (Streamable HTTP transport) and pass three values:

Authorization:        Bearer <YOUR-NANGO-SECRET-KEY>
provider-config-key:  github-app-oauth
connection-id:        <CONNECTION-ID>
Enter fullscreen mode Exit fullscreen mode
  • Authorization: your Nango secret key, held by your backend.
  • provider-config-key: your GitHub integration ID (github-app-oauth).
  • connection-id: the connection for the current user. Fetch it per logged-in user rather than hardcoding it, so each user’s agent acts on their own repositories.

Codex can wire this into your product’s agent for you:

$building-nango-functions-locally Wire my product's AI agent to Nango's MCP server for the github-app-oauth
integration, passing the logged-in user's connection id, so it can read issues and open PRs. Add flexible actions to Nango to make the agent feature complete
Enter fullscreen mode Exit fullscreen mode

An AI agent in a product using Nango MCP tools to create issues, close issues, and add labels, reflected live on GitHub

If you do not have an agent interface in your product yet but want to try the tools, add Nango’s MCP server to Codex itself. codex mcp add does not support custom headers, so add it to ~/.codex/config.toml:

[mcp_servers.nango_github]
url = "https://api.nango.dev/mcp"
bearer_token_env_var = "NANGO_SECRET_KEY"
http_headers = { "connection-id" = "<CONNECTION-ID>", "provider-config-key" = "github-app-oauth" }
Enter fullscreen mode Exit fullscreen mode

Then ask Codex: “Open an issue titled ‘Flaky test in checkout’ in my connected repo using the nango github MCP.” For the patterns that make these tool calls reliable in production, see build reliable tool calls for AI agents.

Tip: you can view detailed action and sync logs on the Nango dashboard.

The Nango dashboard logs showing successful action, sync, and webhook runs for the GitHub integration

Common issues

Issue Cause and fix
401 Bad credentials The token expired or the installation was revoked. Nango refreshes installation tokens (1 hour) and user tokens (8 hours) for you; if the customer removed the installation, they reconnect from your app.
BAD_REFRESH_TOKEN on a user token The client secret was rotated or the installation was revoked. The customer reconnects. See the full breakdown.
403 or 429 with retry-after A primary or secondary rate limit (100 concurrent requests, 900 points per minute). Nango retries with backoff; spread bulk work and avoid firing parallel requests at one installation.
Issue sync contains pull requests GET /issues returns PRs too. Filter on the pull_request field to keep them separate.
Webhook rejected or ignored The X-Hub-Signature-256 HMAC did not match. Confirm the webhook secret on your GitHub App matches the one in Nango; Nango verifies the signature for you.
404 on a repo the user can see The GitHub App installation was not granted that repository. The customer adds it under the installation's repository access settings.
Endpoint returns Not Found only for a GitHub App Some endpoints work only with OAuth Apps. Check for the "Works with GitHub Apps" note on the endpoint in GitHub's docs.
listRecords is empty right after connecting The sync starts only after your app saves the repo metadata, and the first run is asynchronous. Read records once a run completes.

FAQ

Should I use a GitHub App or an OAuth App for a customer-facing product?

Use a GitHub App. It installs per organization or repository with fine-grained permissions and rate limits that scale from 5,000 to 12,500 requests per hour. An OAuth App acts as the authorizing user and suits personal-developer tools.

How do you handle GitHub API rate limits when syncing data?

GitHub allows 5,000 to 12,500 requests per hour, plus secondary limits of 100 concurrent requests and 900 points per minute. Spread bulk work, avoid firing parallel requests at one installation, and retry on 403 or 429 using the retry-after header.

How do you verify GitHub webhooks?

GitHub signs each delivery with an X-Hub-Signature-256 header, an HMAC-SHA256 of the raw request body using your webhook secret. Verify it with a constant-time comparison before trusting the payload, and read the event type from the X-GitHub-Event header.

How long does it take to build a GitHub API integration?

By hand, a production integration with auth, syncs, webhooks, and rate-limit handling takes weeks. With Nango and a coding agent like Codex, the agent writes and tests the same integration against a real connection in about an hour.

Conclusion

A production-grade GitHub API integration for agents comes down to customer auth, incremental sync, writing safely, reacting in real time (signature-verified webhooks), and staying inside two rate-limit systems. Together they become the tools the AI agents in your product call to act on a customer’s GitHub.

With the Nango skill, Codex writes that logic as code from a prompt and tests it against a real connection, while Nango’s runtime handles managed OAuth, durable syncs, webhook verification, retries, and observability. The same workflow covers any of Nango’s 800+ supported APIs, and it scales into just-in-time integrations: integrations built on demand by an agent instead of pre-built for every use case.

Clone the demo project on GitHub to run it end to end, or build your first integration from the quickstart.

Related reading:

Top comments (0)