---
title: "Create branch"
method: POST
path: "/api/apps/{app_id}/branches"
---

# Create branch

`POST /api/apps/{app_id}/branches`

## Request

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

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

Creates a [branch](/developers/references/app-management/get-started/concepts#branches) of the app from its main branch. The branch has its own copy of the app's code, so its changes don't reach main until you [merge the branch](/api-reference/merge-branch).

Set `branch_name` to name the branch, or send `prompt` and Base44 generates a short name from it. `prompt` only names the branch. It isn't sent to the AI. When a generated name is taken, Base44 adds a number to it. A `branch_name` you choose must not belong to another active or merged branch.

The branch starts from main's latest saved state. If the AI is working on main at the time, the branch starts from main as it was before that change. Set `from_message_id` to start from an earlier point instead. Send at least one of `branch_name`, `prompt`, and `from_message_id`.

Branches are created from main only. Sending a `branch_id` returns a 409 with `extra_data.reason` set to `create_branch_requires_main_scope`.

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

This endpoint is limited to 30 requests per minute, shared with Create branch, Delete branch and Merge branch.

<Note>A branch gets changes of its own from chat messages sent to it: pass the branch's `id` as `branch_id` to [Send chat message](/api-reference/send-chat-message). Until it has some, [Merge branch](/api-reference/merge-branch) refuses it with a 409.</Note>

<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. Send only the fields documented here. Other request fields are not supported and their behavior can change.</Warning>

## Path parameters

- `app_id` string, required: ID of the app to create the branch in.

## Query parameters

- `branch_id` string: ID of the branch to work on, as returned by [List branches](/api-reference/list-branches). Omit it to work on the app's main branch.

## Request body

- CreateBranchRequest: The new branch's name, or text to name it from.
  - `branch_name` string, nullable: Name of the branch. It starts with a letter or digit and contains only letters, digits, `.`, `_`, `/` and `-`. It can't contain `..` or `//`, end with `/` or `.`, start with `b44/`, or be `main`, and no part between slashes can start with `.` or end with `.lock`. Leave it out to have Base44 name the branch from `prompt`.
  - `prompt` string, nullable: Text to name the branch from when you leave out `branch_name`. Base44 generates a short name from it. An empty string names the branch after your first name and today's date.
  - `from_message_id` string, nullable: ID of a message in main's conversation, from [Read conversation messages](/api-reference/read-conversation-messages). The branch starts from the app as it was when that message was sent, instead of from main's latest state. Without `branch_name`, the branch is named after the last user message before that one, and `prompt` is ignored.

## Response `200`

The new branch.

- BranchSummary: 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.
  - `session_id` string, nullable, required: ID of the [session](/api-reference/get-session) this branch belongs to, or `null` for a branch Base44 hasn't put in a session 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.

## Other responses

- `400`: `branch_name` is `main`, or you set `from_message_id` on an app imported from GitHub, or the message's saved version belongs to a branch rather than main.
- `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. The code is `branches_not_supported` when the app's type doesn't support branches.
- `404`: App not found, `from_message_id` isn't in main's conversation or has no saved version to start from, or no branch you can see has this `branch_id`.
- `409`: An active or merged branch is already named `branch_name`, or you sent a `branch_id` (`extra_data.reason` is `create_branch_requires_main_scope`).
- `422`: None of `branch_name`, `prompt`, and `from_message_id` is set, `branch_name` breaks the naming rules or is over 100 characters, or `from_message_id` is over 64 characters.
- `429`: Rate limit exceeded. The base limit is 30 requests per minute. See [Rate limits](/developers/references/apps-api/get-started/rate-limits) for the multiplier your plan gets.

## Changes

- **2026-10-28** `77fa614f2e21`: 1 info
  - added the required property `session_id` to the response with the `200` status
- **2026-10-25** `835dda629ead`: 1 info
  - added the new optional `query` request parameter `branch_id`
- **2026-10-11** `80287813ab84`: 1 info
  - the endpoint scheme security `PersonalAccessTokenAuth` was added to the API
- **2026-10-08** `16acfcde4e33`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/base44/apis/base44-app-management-api/changes/api/apps/:app_id/branches/post.md)

---

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