---
title: "Pull changes from GitHub"
method: POST
path: "/api/apps/{app_id}/github/sync"
---

# Pull changes from GitHub

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

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

Pulls new commits from the connected GitHub repository into the app.

Call this after someone pushes to the repository, or before you read the app's code, so Base44 is working from the latest version. It applies only what is new since the last pull, and does nothing when the app is already up to date.

A failed pull is reported in the response body rather than as an error, so read `synced` and `error`. Base44 doesn't record the commits it couldn't apply, so the next pull picks them up again rather than skipping past them. A pull that fails late can already have added a chat message or a checkpoint, and retrying repeats those.

A merge conflict means the repository's commits and the app's own changes touch the same lines. Hand it to [Resolve GitHub sync conflicts](/api-reference/resolve-github-sync-conflicts).

<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 whose GitHub sync this affects.

## Response `200`

The outcome of the pull.

- 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

- `401` — Missing or invalid credentials.
- `403` — You don't have access to this app, or you used a workspace API key. These endpoints take a personal API key.
- `404` — App not found.
- `429` — Rate limit exceeded. The base limit is 20 requests per minute, and this endpoint shares it with [Resolve GitHub sync conflicts](/api-reference/resolve-github-sync-conflicts). See [Rate limits](/developers/references/app-management/get-started/rate-limits) for the multiplier your plan gets.

## Changes

- **2026-08-30** `394136a6cdd4` — 1 info
  - removed the non-success response with the status `422`
- **2026-08-27** `31ef75eb64ab` — 1 info
  - endpoint added

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

---

[API](https://skmtc.dev/idealspot/apis/base44-app-management-api.md) · [All operations](https://skmtc.dev/idealspot/apis/base44-app-management-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/idealspot/base44-app-management-api/revisions/56dc45634956/schema)
