---
title: "Reconnect a GitHub repository"
method: POST
path: "/api/apps/{app_id}/github/reconnect"
---

# Reconnect a GitHub repository

`POST /api/apps/{app_id}/github/reconnect`

<Info>This API is in beta. Endpoints, fields, and behavior may still change, so avoid depending on it in production.</Info>

Reconnects the app to the GitHub repository it was disconnected from.

Only the app's owner can reconnect, and the workspace plan has to include the GitHub integration. There's something to reconnect only after a user disconnected the app, so check `previous_repository` in [Get GitHub connection](/api-reference/get-github-connection) first.

Base44 compares the app's history with the repository's default branch and brings whichever side is behind up to date:
- When they match, nothing moves.
- When the app has newer commits, Base44 pushes them to the repository.
- When the repository has newer commits, Base44 pulls them into the app.

When both sides have new commits, or their histories are unrelated, the reconnect is refused and the app stays disconnected. A successful reconnect also turns automatic sync back on and copies the app's open [branches](/developers/references/app-management/get-started/concepts#branches) to the repository.

Reinstalling the webhook that tells Base44 about new commits can fail without failing the reconnect, so check `webhook_active` in [Get GitHub connection](/api-reference/get-github-connection) afterwards. Check the same call before you retry a reconnect whose response you lost. One that already succeeded answers a retry with `no_previous_repository`.

A refused reconnect leaves the app disconnected, and its body is `{"error": {"code", "message", "details"}}`. Branch on `code`, whose values are listed with each error response.

A pull that fails after the reconnect is reported in `sync` rather than as an error. The repository is connected by then, so retry the pull with [Pull changes from GitHub](/api-reference/pull-changes-from-github).

<Warning>The response includes fields beyond the ones documented here. Don't rely on undocumented response fields, as they can change at any time.</Warning>

## Path parameters

- `app_id` string, required — ID of the app to reconnect to the GitHub repository it was disconnected from.

## Response `200`

The app is connected to its repository again.

- GitHubReconnectResult — Result of reconnecting the app to the GitHub repository it was disconnected from.
  - `direction` 'none' | 'base44_to_github' | 'github_to_base44', required — Which side Base44 brought up to date. Either `none` (the two already matched), `base44_to_github` (Base44 pushed the app's newer commits), or `github_to_base44` (Base44 pulled the repository's newer commits).
  - `repo_full_name` string, required — Full repository name, as `owner/repo`.
  - `repo_url` string, required — URL of the repository on GitHub.
  - `base44_head` string, required — The app's latest commit when the reconnect started.
  - `github_head` string, required — Head of the repository's default branch when the reconnect started.
  - `sync` GitHubPullResult — Outcome of a pull from the connected repository.
    - `synced` boolean, required — Whether this call applied new commits to the app.
    - `already_up_to_date` boolean, required — Whether the repository's head was already the last commit Base44 pulled, so there was nothing to do.
    - `commits_pulled` integer, required — How many commits `commits` holds, so commits Base44 pushed itself aren't counted. The value is `0` when nothing was pulled.
    - `latest_commit_hash` string, nullable — Repository head after the pull, or `null` when nothing was pulled.
    - `commits` GitHubPulledCommit[] — The commits this call applied, oldest first. Commits Base44 pushed itself are left out, so a pull of only those comes back with an empty list.
      - `sha` string, required — Full commit SHA.
      - `short_sha` string, required — Short form of the commit SHA.
      - `message` string, required — Commit message.
      - `author_name` string, required — The author's GitHub username when GitHub reports one, otherwise the name recorded in the commit.
      - `author_email` string, nullable — Email recorded as the commit's author, or `null` when GitHub doesn't report one.
      - `timestamp` string, required — When the commit was authored, in ISO 8601.
      - `url` string, required — URL of the commit on GitHub.
    - `files_summary` GitHubPulledFiles — How much the pulled commits changed.
      - `total_files` integer, required — Files changed across the pulled commits.
      - `files_with_content` integer, required — Changed files whose new content Base44 applied to the app.
      - `files_metadata_only` integer, required — Changed files Base44 recorded without their content, because GitHub didn't return a usable diff for them.
      - `files_deleted` integer, required — Files removed from the app by the pull.
      - `total_additions` integer, required — Lines added across the pulled commits.
      - `total_deletions` integer, required — Lines removed across the pulled commits.
    - `error` string, nullable — Why the pull didn't happen, or `null` when it succeeded. One of `not_connected`, `no_installation`, `sync_in_progress`, `connection_error`, `merge_conflict`, `sandbox_sync_failed`, `rate_limit_exceeded`, `rate_limit_low`, `github_api_error` or `unexpected_error`.
    - `error_message` string, nullable — Human-readable explanation of `error`, or `null` when the pull succeeded.
    - `duration_ms` integer, nullable — How long the pull took, in milliseconds, or `null` when Base44 recorded no duration for it.

## Other responses

- `400` — The app has nothing to reconnect to, because it's connected already, a user never disconnected it, or its repository was deleted on GitHub. The `code` is `no_previous_repository`.
- `401` — Missing or invalid credentials.
- `402` — The app's workspace plan doesn't include the GitHub integration. The `code` is `capability_required`.
- `403` — You don't have access to this app, or you used a workspace API key. The other refusals carry a `code`: - `owner_required` when you aren't the app's owner. - `installation_unavailable` or `push_access_missing` when the Base44 GitHub App can't write to the repository any more. - `github_org_not_allowed` when the app's workspace doesn't approve the repository's GitHub organization.
- `404` — App not found, or the repository no longer exists under the name it was connected as. Only the second carries a `code`, which is `repository_not_found`.
- `409` — The reconnect was refused, and `code` says why: - `histories_diverged` when both the app and the repository have new commits since they last matched. - `unrelated_histories` when the repository's history doesn't share a starting point with the app's. - `repository_moved` when the repository was renamed or transferred. `details` holds the old and new names. - `default_branch_changed` when the repository's default branch changed. `details` holds both branch names. - `workspace_mismatch` when the app moved to a different workspace after it was connected. - `workspace_installation_inactive` when the workspace's GitHub installation was disconnected. - `app_already_processing` or `branch_turn_in_progress` when the app or one of its branches is busy. - `branch_refs_rejected` when one of the app's open branches has changes on GitHub that Base44 can't fast-forward.
- `502` — GitHub couldn't be reached or read (`github_unavailable` or `history_unavailable`), or didn't accept the app's commits (`push_failed`). Nothing was activated, so you can retry.

## Changes

> 18 revisions in range; 1 not diffed.

- **2026-09-28** `28fc82924122` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/adexad/apis/base44-app-management-api/changes/api/apps/:app_id/github/reconnect/post.md)

---

[API](https://skmtc.dev/adexad/apis/base44-app-management-api.md) · [All operations](https://skmtc.dev/adexad/apis/base44-app-management-api/llms.txt) · [OpenAPI document](https://skmtc.dev/adexad/apis/base44-app-management-api/revisions/28fc82924122?raw)
