---
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 repository into the app.

Call this after someone pushes to the repository, or before reading the app's code, to bring Base44 up to date. It compares the repository's head with the last commit Base44 pulled, applies the diff to the app's files, updates the app's sandbox, and records the new head. With nothing new to apply it returns `synced: false` and `already_up_to_date: true`.

<Warning>A failed pull still returns HTTP 200. Read `synced` and `error` instead of the status code. An app with no active connection comes back `synced: false` with `error: not_connected` rather than a 404.</Warning>

`error: 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). `sync_in_progress` means another pull, or a builder turn, holds the app right now, so retry it. On any error Base44 leaves the commit it last pulled where it was, so the next pull starts over from the same place rather than skipping the commits that failed.

This endpoint allows 20 requests per minute per caller, shared with [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>

<Note>This endpoint accepts a personal API key. Workspace API keys are not authorized for it and are rejected with a 403.</Note>

## 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 — `true` when 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. `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. `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.
- `422` — Validation Error
- `429` — Rate limit exceeded (20 requests per minute).

---

[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/31ef75eb64ab/schema)
