---
title: "Import a Claude Code or Codex session"
method: POST
path: "/api/apps/{app_id}/imported/session-imports"
---

# Import a Claude Code or Codex session

`POST /api/apps/{app_id}/imported/session-imports`

## Request

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

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

Imports a Claude Code or Codex session into an imported app as a Base Code branch, with the session's conversation in that branch's chat. You continue the work there with the AI. The `base44 sessions import` CLI command calls this endpoint.

Send the session file as `file` in a `multipart/form-data` body. Base Code reads a Claude Code transcript, the `.jsonl` file under `~/.claude/projects/`, or a Codex rollout, the `rollout-*.jsonl` file under `~/.codex/sessions/`. The file can be up to 50 MB.

The conversation is cut at the prompt that asked for the import, so that prompt and everything after it are left out. Only typed messages, the images pasted into them, and the AI's replies are kept, and at most the newest 400 turns are written. Thinking, tool arguments, and tool output, including its screenshots, are dropped. The newest 20 pasted PNG, JPEG, GIF, and WebP images are attached to their messages. A message whose images weren't imported, because there were more or they couldn't be read or stored, says how many.

The session continues on its own branch when that branch is in the app's GitHub repository and isn't the default branch. Base Code adopts that branch as it is, so stop working on it locally. If Base Code already has an active branch with that name, the import is refused and nothing is written. In every other case Base Code creates a new branch named after the session's first message. It starts from the session's branch when that's in the repository, and from the default branch when it isn't. `continued` and `source_ref` say which one happened.

Importing a session again adds only what's new. When the same session was imported before into a branch that's still active, Base Code writes only the messages that come after the ones it already has, after anything said on the branch since, and sets `reimported` to `true`. `turn_count` then counts the new messages, so `0` means the branch was already up to date. The code isn't touched: the branch already follows the session's pushed commits. If that branch was merged or archived, the import creates a new branch as above.

Authenticate with a personal access token, sent as `Authorization: Bearer <token>`. Where the user isn't signed in, such as on a cloud machine, send the one-time import key that Base Code's Import session dialog creates in its place. The key starts with `b44imp_`, works once and only for the app it was created for, and expires after 10 minutes. The import then runs as the user who opened the dialog.

Send an `Idempotency-Key` header, such as a UUID, and repeat it when you retry after a lost response, a `409` `conflict`, or a `5xx`. A retry with the same key, file, and `source_branch` returns the first import's response and writes nothing. Only a successful import is remembered, for 24 hours, so a retry after an error imports again. An upload with an import key can't be retried at all: the key works once, so a retry gets a `401`.

## Path parameters

- `app_id` string, required: ID of the imported app to import the session into.

## Headers

- `Idempotency-Key` string: A value you generate for this import, 8 to 100 characters, such as a UUID. Send the same value when you retry the import, and a new one for every other import. A retry with the same value, file, and `source_branch` within 24 hours returns the first response instead of importing again. Keys are scoped to the user and the app.

## Request body `multipart/form-data`

- SessionImportUpload: A Claude Code or Codex session to import.
  - `file` string, binary, required: The session file, a Claude Code `.jsonl` transcript or a Codex `rollout-*.jsonl` file of up to 50 MB.
  - `source_branch` string, nullable: The Git branch the session is on now. It wins over the branch recorded in the file, which can predate a push. Leave it out to use the file's branch.

## Response `200`

The branch the session was imported into.

- SessionImportResponse
  - `branch_id` string, required: ID of the Base Code branch the session was imported into.
  - `branch_name` string, required: Name of that branch. When `continued` is `true`, it's the session's own Git branch.
  - `source` 'claude_code' | 'codex', required: The tool that recorded the session. Either `"claude_code"` or `"codex"`.
  - `turn_count` integer, required: Number of messages written to the branch's chat by this import.
  - `branch_url` string, required: Path of the branch in the app editor. Append it to the Base44 address to open it.
  - `continued` boolean, required: Whether the session continues on its own branch. The value is `true` when Base Code adopted the session's branch and `false` when it created a new branch from `source_ref`.
  - `source_ref` string, required: Git branch the Base Code branch comes from. It's the session's branch when that's in the repository, and the repository's default branch when it isn't.
  - `reimported` boolean: Whether this session was imported into the branch before. When `true`, only the messages added since then were written and `turn_count` counts them, so `0` means the branch was already up to date.

## Other responses

- `400`: `invalid_request`: The file is empty.
- `401`: `unauthenticated`: The credentials are missing or invalid, or were sent as an `api_key` query parameter. An import key also gets this when it's invalid, expired, or already used, or when the user who created it has signed out since.
- `403`: `forbidden`: The credential's user doesn't have write access to the app, or the import key was created for another app. A read-only personal access token is refused, and so is a workspace API key. `route_does_not_accept_keys`: A workspace API key that runs as its workspace's owner is refused.
- `404`: `not_found`: The app doesn't exist, isn't an imported app, or session import isn't available for it.
- `409`: `branch_exists`: Base Code already has an active branch for the session's branch, and nothing was written. `details.branch_name` and `details.branch_url` point at it. `repository_not_connected`: The app isn't connected to its GitHub repository. `conflict`: The app or its repository changed while the branch was being created. Retry the import with the same `Idempotency-Key`. `idempotency_key_mismatch`: The `Idempotency-Key` was already used with a different file or `source_branch`. `idempotency_key_in_use`: An import with the same `Idempotency-Key` is still running. Retry it shortly. `session_changed`: The session was imported into an active branch before, but its earlier messages changed since, so Base Code can't tell which ones are new. Nothing was written. Import it into a new branch from Base Code's Import session dialog. `wrong_session`: The import key was created to add newer messages to the branch in `details.branch_url`, and this session isn't the one imported into it. Nothing was written. `branch_busy`: The branch the session was imported into is still running a turn. Retry when it finishes. `auth_required_for_workspace`, `sso_required_for_workspace`, or `mfa_required_for_workspace`: The app's workspace needs the user who created the import key to sign in again.
- `411`: `content_length_required`: The request has no `Content-Length` header.
- `413`: `file_too_large`: The request or the file is larger than 50 MB.
- `422`: `unsupported_file`: The file isn't a Claude Code or Codex session, or it has nothing to import before the import prompt. `repository_mismatch`: The session was recorded in a different repository from the app's. `invalid_request`: `file` is missing, `source_branch` is longer than 255 characters, or `Idempotency-Key` is shorter than 8 or longer than 100 characters.
- `429`: `rate_limited`: The base limit is 6 imports per minute, scoped to the user, and reported in the `X-RateLimit-*` headers. Retry after the number of seconds in `Retry-After`. See [Rate limits](/developers/references/apps-api/get-started/rate-limits) for the multiplier your plan gets.

## Changes

- **2026-10-29** `01d69381668e`: 1 info
  - added the optional property `reimported` to the response with the `200` status
- **2026-10-28** `21162ba67ca7`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/idealspot/apis/base44-app-management-api/changes/api/apps/:app_id/imported/session-imports/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.dev/idealspot/apis/base44-app-management-api/revisions/b5b4ebd82a1e?raw)
