---
title: "Update branch from main"
method: POST
path: "/api/apps/{app_id}/branches/{branch_id}/sync-from-main"
---

# Update branch from main

`POST /api/apps/{app_id}/branches/{branch_id}/sync-from-main`

## Request

- Base URL: `https://app.base44.com`
- URL: `https://app.base44.com/api/apps/{app_id}/branches/{branch_id}/sync-from-main`
- Auth: HTTP bearer

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

Brings main's latest changes into an active branch. When main's code changed, Base44 merges it into the branch. Messages sent on main since the branch was created or last updated are added to the branch's conversation as context for the AI. When nothing changed on main, nothing happens and `updated` is `false`.

If main's changes conflict with the branch's, the AI resolves the conflicts on the branch before the request returns. That's an AI turn: it uses credits like a chat message, and the request can stay open for several minutes. If the AI needs your input to finish, `sync_status.sync_state` is `needs_input`. The branch then stays locked until you answer in the Base44 editor, and it can't be updated, merged, or deleted until then. If the AI can't resolve the conflicts, the request fails and the branch is restored to how it was before the update.

In this response, `branch.created_by_name` is always `null`. [Get branch](/api-reference/get-branch) returns it.

This endpoint is limited to 10 requests per minute.

<Tip>A 409 response carries an `extra_data.reason` code that says why the request was refused.</Tip>

<Note>This endpoint accepts a personal API key belonging to a user with editor access to the app. A read-only key is refused, and workspace API keys are not accepted.</Note>

<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

- `branch_id` string, required: ID of the branch, as returned by [List branches](/api-reference/list-branches).
- `app_id` string, required: ID of the app the branch belongs to.

## Response `200`

The branch after the update.

- BranchSyncResult: The branch after the update.
  - `branch` BranchSummary, required: A branch of an app.
    - `id` string, required: ID of the branch.
    - `app_id` string, required: ID of the app the branch belongs to.
    - `branch_name` string, required: Name of the branch.
    - `status` 'active' | 'merged' | 'deleted', required: `active` while the branch can still be worked on, `merged` once it was merged into main, and `deleted` once it was deleted.
    - `run_state` BranchRunState, required
      - `state` 'ready' | 'processing' | 'error', required: `processing` while the AI is working on the branch, `ready` once it's idle, and `error` when the last turn on the branch failed.
      - `details` string, nullable, required: Short note about the state, such as why the last turn failed, or `null` when there's nothing to report.
      - `last_updated_date` string, date-time, required: When the state last changed, as a UTC timestamp in ISO 8601 format.
    - `code_state` 'unchanged' | 'changed', required: `unchanged` when the branch has no code changes of its own to merge into main. `changed` otherwise, including when Base44 can't tell yet.
    - `base_checkpoint_id` string, nullable, required: ID of the main [checkpoint](/api-reference/list-checkpoints) the branch started from, or `null` if the app had no checkpoint yet.
    - `created_by_id` string, required: ID of the user who created the branch.
    - `created_by_name` string, nullable, required: Display name of the user who created the branch, or the part of their email before the `@` when they have no name. `null` when Base44 can't name them, for example when their account no longer exists.
    - `created_date` string, date-time, required: When the branch was created, as a UTC timestamp in ISO 8601 format.
    - `merged_at` string, date-time, nullable, required: When the branch was merged into main, as a UTC timestamp in ISO 8601 format, or `null` if it wasn't.
    - `merged_by_id` string, nullable, required: ID of the user who merged the branch, or `null` if it wasn't merged or Base44 doesn't know who did, as for a branch whose pull request was merged on GitHub.
    - `static_preview_url` string, required: URL of the branch's preview. It shows the branch only while it's active and once it has been built.
  - `sync_status` BranchSyncStatus, required: How the branch stands against main.
    - `new_main_message_count` integer, required: How many chat messages people sent on main since the branch was created or last updated from main.
    - `main_code_changed` boolean, required: `true` when main's code changed since the branch was created or last updated from main.
    - `conflict_state` 'clear' | 'overlap' | 'unavailable', required: Whether updating the branch from main is expected to conflict. `clear` when main's code hasn't changed, so an update can't conflict. `overlap` when the update is expected to conflict, or while conflicts from an update are being resolved. `unavailable` when Base44 can't tell, including while an update runs. Once main's code has changed, it's never `clear`, even when the update would apply cleanly.
    - `sync_state` 'idle' | 'updating' | 'resolving' | 'needs_input', required: `idle` when no update is running. `updating` while main's changes are being applied, `resolving` while the AI resolves conflicts, and `needs_input` when the AI needs an answer to finish resolving them. Answer it in the Base44 editor. Until the state is back to `idle`, the branch can't be merged or deleted.
    - `blocked_reason` 'app_processing' | 'branch_processing', nullable, required: Why [Update branch from main](/api-reference/update-branch-from-main) would be refused right now: `app_processing` while the AI is working on main, and `branch_processing` while it's working on the branch. `null` when neither applies. An update is also refused while `sync_state` is `resolving` or `needs_input`.
  - `updated` boolean, required: `false` when the branch was already up to date with main, so nothing changed. `true` when the update was applied, or when it's waiting for your input (`sync_status.sync_state` is `needs_input`).

## Other responses

- `400`: The update needs the AI to resolve conflicts, and you've run out of credits.
- `401`: Missing or invalid credentials.
- `403`: You don't have editor access to this app, the app is blocked, your API key is read-only, or you used a workspace API key.
- `404`: App not found, or the app has no active branch with this ID.
- `409`: The branch can't be updated right now. `extra_data.reason` is `app_processing` or `branch_processing` while the AI is working on main or on the branch, `branch_sync_in_progress` while another update runs or waits for input, and `branch_sync_branch_moved` when the branch changed during the update. Any other reason means recent changes are still being saved. Try again shortly.
- `429`: Rate limit exceeded. The base limit is 10 requests per minute. See [Rate limits](/developers/references/apps-api/get-started/rate-limits) for the multiplier your plan gets.

## Changes

> 58 revisions in range; 1 not diffed.

- **2026-10-12** `5e139db2e643`: 1 info
  - the endpoint scheme security `PersonalAccessTokenAuth` was added to the API
- **2026-10-09** `7843e6425fe2`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/adexad/apis/base44-app-management-api/changes/api/apps/:app_id/branches/:branch_id/sync-from-main/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/fa29e915c226?raw)
