> ## Documentation Index
> Fetch the complete documentation index at: https://docs.base44.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Save several app files

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

Saves several files into the app in one call, the way the builder's visual editor does.

Send up to 50 files. Every path is validated before anything is written, so one bad path fails the whole batch with a 400 and leaves the app untouched. An empty `files` list is a 400 rather than a no-op.

This route never deploys, so it refuses backend code: a path under `functions/` answers 422 rather than writing source that the live function wouldn't match. Use [Save an app file](/api-reference/save-an-app-file) for those, one at a time, and this one for the frontend files a visual edit touches.

Unlike the single-file route, this one follows the branch you are working on, so the writes land on that branch's own sandbox rather than on main.

The response is the app document as it stands after the change, the same shape [Get app](/api-reference/get-app) returns.

<Note>This endpoint accepts a personal API key. Workspace API keys are not authorized for it and are rejected with a 403.</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>



## OpenAPI

````yaml /developers/references/app-management/app-management-openapi.json post /api/apps/{app_id}/coding/write-batch
openapi: 3.1.0
info:
  title: Base44 App Management API
  version: 1.0.0
servers:
  - url: https://app.base44.com
security:
  - ApiKeyAuth: []
paths:
  /api/apps/{app_id}/coding/write-batch:
    post:
      summary: Save several app files
      description: >-
        <Info>This API is in beta. Endpoints, fields, and behavior may still
        change, so avoid depending on it in production.</Info>


        Saves several files into the app in one call, the way the builder's
        visual editor does.


        Send up to 50 files. Every path is validated before anything is written,
        so one bad path fails the whole batch with a 400 and leaves the app
        untouched. An empty `files` list is a 400 rather than a no-op.


        This route never deploys, so it refuses backend code: a path under
        `functions/` answers 422 rather than writing source that the live
        function wouldn't match. Use [Save an app
        file](/api-reference/save-an-app-file) for those, one at a time, and
        this one for the frontend files a visual edit touches.


        Unlike the single-file route, this one follows the branch you are
        working on, so the writes land on that branch's own sandbox rather than
        on main.


        The response is the app document as it stands after the change, the same
        shape [Get app](/api-reference/get-app) returns.


        <Note>This endpoint accepts a personal API key. Workspace API keys are
        not authorized for it and are rejected with a 403.</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>
      operationId: write_batch_api_api_apps__app_id__coding_write_batch_post
      parameters:
        - name: app_id
          in: path
          required: true
          schema:
            type: string
            description: ID of the app whose code to change.
            title: App Id
          description: ID of the app whose code to change.
          example: 6820f3a4e7b91d003c45a1f2
      requestBody:
        required: true
        content:
          application/json:
            schema:
              title: SaveAppFiles
              type: object
              required:
                - files
              properties:
                files:
                  type: array
                  minItems: 1
                  maxItems: 50
                  description: >-
                    The files to save, 1 to 50 of them. All are validated before
                    any is written.
                  items:
                    type: object
                    title: SaveAppFilesEntry
                    required:
                      - file_path
                      - content
                    properties:
                      file_path:
                        type: string
                        description: Path of the file, relative to the app root.
                      content:
                        type: string
                        description: >-
                          Full contents to save. An empty string deletes the
                          file, which is this endpoint's convention rather than
                          a way to blank one.
            example:
              files:
                - file_path: src/pages/About.jsx
                  content: |
                    export default function About() {
                      return <h1>About</h1>;
                    }
                - file_path: src/pages/Home.jsx
                  content: |
                    export default function Home() {
                      return <h1>Home</h1>;
                    }
      responses:
        '200':
          description: The app after the writes.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AppSummary'
        '400':
          description: >-
            `files` is empty, holds more than 50 entries, has a path that
            escapes the app or uses a legacy schema, workflow or email location,
            or a configuration file with invalid JSON.
        '401':
          description: Missing or invalid credentials.
        '403':
          description: >-
            You don't have access to this app, or you used a workspace API key.
            Writing a backend function also needs a Builder plan or higher on
            the app's workspace.
        '404':
          description: App not found.
        '409':
          description: >-
            The app is on a branch this change can't be made on: a branch that
            has been merged or closed, a protected main, or a path the branch
            refuses.
        '422':
          description: >-
            One of the paths is backend code, which this route can't write
            because it never redeploys.
components:
  schemas:
    AppSummary:
      properties:
        id:
          anyOf:
            - type: string
            - type: 'null'
          title: Id
          description: ID of the app.
          example: 6820f3a4e7b91d003c45a1f2
        name:
          anyOf:
            - type: string
            - type: 'null'
          title: Name
          description: Display name of the app.
          example: My CRM
        slug:
          anyOf:
            - type: string
            - type: 'null'
          title: Slug
          description: >-
            URL slug for the app, auto generated from the name and app ID or set
            to a custom value, or `null` if the app has no slug yet. The
            published URL is built from it.
          example: my-crm-3c45a1f2
        user_description:
          anyOf:
            - type: string
            - type: 'null'
          title: User Description
          description: >-
            Description of the app, or `null` if none was set. On a newly
            created app this holds the original prompt text.
          example: A CRM to track leads and deals
        created_by:
          anyOf:
            - type: string
            - type: 'null'
          title: Created By
          description: Email of the user who created the app.
          example: developer@example.com
        created_date:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Created Date
          description: Time the app was created, as a UTC timestamp in ISO 8601 format.
          example: '2026-08-01T09:15:00'
        updated_date:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Updated Date
          description: >-
            Time the app document was last written, as a UTC timestamp in ISO
            8601 format.
          example: '2026-08-02T14:30:00'
        status:
          anyOf:
            - $ref: '#/components/schemas/AppStatusResponse'
            - type: 'null'
          description: >-
            The app's current build status. Poll while a build is in progress to
            watch it finish. This tracks building, not publishing.
        last_deployed_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Last Deployed At
          description: >-
            Time the app was last published, as a UTC timestamp in ISO 8601
            format, or `null` if it has never been published.
          example: '2026-08-02T14:30:00'
        screenshot_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Screenshot Url
          description: >-
            URL of a screenshot of the published app. Captured shortly after
            each publish, so it can briefly lag or be `null` right after
            publishing.
          example: https://storage.base44.com/screenshots/6820f3a4e7b91d003c45a1f2.png
        preview_screenshot_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Preview Screenshot Url
          description: >-
            URL of a preview screenshot taken before publishing, distinct from
            `screenshot_url`, or `null` if none has been captured.
          example: https://storage.base44.com/previews/6820f3a4e7b91d003c45a1f2.png
      type: object
      title: AppSummary
      description: An app in a workspace, limited to the properties the caller requested.
    AppStatusResponse:
      properties:
        state:
          type: string
          enum:
            - ready
            - processing
            - error
          title: State
          description: >-
            Where the app is in its build lifecycle. Ready means idle with no
            build in progress, processing means the app is being generated or
            modified, and error means the last build failed. This tracks
            building, not publishing.
          example: ready
        details:
          anyOf:
            - type: string
            - type: 'null'
          title: Details
          description: >-
            Human readable note about the current state, such as what is being
            processed or why it failed, or `null` when there is nothing to
            report.
          example: Publishing app
        request_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Request Id
          description: >-
            ID of the request that last changed the status, or `null` if the
            status has never changed. Useful when reporting an issue.
          example: a1b2c3d4e5f67890abcdef12
        last_updated_date:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Last Updated Date
          description: >-
            Time the status was last updated, as a UTC timestamp in ISO 8601
            format.
          example: '2026-08-02T14:30:00Z'
        error_source:
          anyOf:
            - type: string
            - type: 'null'
          title: Error Source
          description: >-
            Where the failure originated when `state` is `error`, or `null`
            otherwise. A value of `paywall` means the work was blocked because
            the app's workspace has no credits left.
          example: build
        paywall_context:
          anyOf:
            - $ref: '#/components/schemas/PaywallStatusContextResponse'
            - type: 'null'
          description: >-
            Present when the operation was blocked by a plan limit, describing
            what was evaluated, or `null` otherwise.
      type: object
      required:
        - state
      title: AppStatusResponse
      description: The app's current build status.
    PaywallStatusContextResponse:
      properties:
        billing_organization_id:
          type: string
          title: Billing Organization Id
          description: ID of the billing organization the paywall was evaluated against.
          example: 67e0b12c4d8a3f005b21c9e4
        user_id:
          type: string
          title: User Id
          description: ID of the user the paywall was evaluated for.
          example: 6706af53b9c1e2004a37d85f
        evaluated_at:
          type: string
          format: date-time
          title: Evaluated At
          description: >-
            Time the paywall condition was evaluated, as a UTC timestamp in ISO
            8601 format.
          example: '2026-08-02T14:30:00Z'
      type: object
      required:
        - billing_organization_id
        - user_id
        - evaluated_at
      title: PaywallStatusContextResponse
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: api_key
      description: Personal API key.

````