> ## 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.

> ## Agent Instructions
> Internal links on these pages omit the .md extension. Append .md to a docs page URL, or send an Accept: text/markdown header, to get that page as markdown.

# Upsert entity records

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

Creates or updates up to 500 records in one of the app's entities in one call, matching them to stored records by the fields you name in `key`.

For each record you send, a stored record with the same values in every `key` field is updated, and otherwise a new record is created. For example, with `"key": "order_number"`, re-sending an order updates it instead of adding a copy, so a sync job can send the same records again safely. An update merges like [Update entity record](/api-reference/update-entity-record), so a field you leave out keeps its value. Only the fields the entity's schema declares are stored, so a misspelled name is left out of the record instead of failing the call. Base44 always assigns `id`, `created_date`, `updated_date`, `created_by`, and `created_by_id` automatically, and ignores any of them you send.

`key` fields must be fields the entity's schema declares as a string, number, integer or boolean, and every record needs a value for each of them. Values are compared as the schema stores them, so `"42"` matches a stored `42` in a number field. When two records you send share a key, the later one wins. When several stored records share a key, the newest is updated.

Row-level security applies. Only stored records the entity's `rls` update rule lets you change are matched, so a record you can't change gets a new copy rather than an update, and new records must be covered by the `rls` create rule. Every record is checked before any is written, and one that fails rejects the call. If a call fails while it's writing, some records can already be stored, and sending it again finishes the job. Wait for the first call to finish before you retry: there's no `Idempotency-Key`, so two calls running at once can both create the same new record.

`records` in the response lists the created records first, then the updated ones. Like [Create entity records](/api-reference/create-entity-records), this doesn't trigger the app's webhooks, automations, or workflows.

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



## OpenAPI

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


        Creates or updates up to 500 records in one of the app's entities in one
        call, matching them to stored records by the fields you name in `key`.


        For each record you send, a stored record with the same values in every
        `key` field is updated, and otherwise a new record is created. For
        example, with `"key": "order_number"`, re-sending an order updates it
        instead of adding a copy, so a sync job can send the same records again
        safely. An update merges like [Update entity
        record](/api-reference/update-entity-record), so a field you leave out
        keeps its value. Only the fields the entity's schema declares are
        stored, so a misspelled name is left out of the record instead of
        failing the call. Base44 always assigns `id`, `created_date`,
        `updated_date`, `created_by`, and `created_by_id` automatically, and
        ignores any of them you send.


        `key` fields must be fields the entity's schema declares as a string,
        number, integer or boolean, and every record needs a value for each of
        them. Values are compared as the schema stores them, so `"42"` matches a
        stored `42` in a number field. When two records you send share a key,
        the later one wins. When several stored records share a key, the newest
        is updated.


        Row-level security applies. Only stored records the entity's `rls`
        update rule lets you change are matched, so a record you can't change
        gets a new copy rather than an update, and new records must be covered
        by the `rls` create rule. Every record is checked before any is written,
        and one that fails rejects the call. If a call fails while it's writing,
        some records can already be stored, and sending it again finishes the
        job. Wait for the first call to finish before you retry: there's no
        `Idempotency-Key`, so two calls running at once can both create the same
        new record.


        `records` in the response lists the created records first, then the
        updated ones. Like [Create entity
        records](/api-reference/create-entity-records), this doesn't trigger the
        app's webhooks, automations, or workflows.


        <Note>This endpoint accepts a personal API key belonging to a user with
        access to the app. A read-only key is refused, and workspace API keys
        are not accepted.</Note>
      operationId: upsert_entities_api_apps__app_id__entities__entity_name__upsert_post
      parameters:
        - name: app_id
          in: path
          required: true
          schema:
            type: string
            description: ID of the app that owns the entity.
            title: App Id
          description: ID of the app that owns the entity.
          example: 6820f3a4e7b91d003c45a1f2
        - name: entity_name
          in: path
          required: true
          schema:
            type: string
            description: >-
              Name of the entity, exactly as [List entity
              schemas](/api-reference/list-entity-schemas) reports it. Don't
              pass `User` here. It doesn't fail, but it reads and writes a
              separate, disconnected set of records stored under that name, not
              the app's real user accounts, which are managed through their own
              endpoints.
            title: Entity Name
          description: >-
            Name of the entity, exactly as [List entity
            schemas](/api-reference/list-entity-schemas) reports it. Don't pass
            `User` here. It doesn't fail, but it reads and writes a separate,
            disconnected set of records stored under that name, not the app's
            real user accounts, which are managed through their own endpoints.
          example: Invoice
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertPayload'
      responses:
        '200':
          description: >-
            How many records were created and updated, and the records
            themselves.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: UpsertEntityRecordsResult
                description: >-
                  How many records were created and updated, and the records
                  themselves.
                properties:
                  created:
                    type: integer
                    description: Number of new records created.
                    example: 1
                  updated:
                    type: integer
                    description: Number of stored records updated.
                    example: 1
                  records:
                    type: array
                    items:
                      additionalProperties: true
                      description: One record in one of an app's entities.
                      properties:
                        id:
                          anyOf:
                            - type: string
                            - type: 'null'
                          description: >-
                            ID of the record. Pass it as `entity_id` to [Get
                            entity record](/api-reference/get-entity-record),
                            [Update entity
                            record](/api-reference/update-entity-record) or
                            [Delete entity
                            record](/api-reference/delete-entity-record).
                          example: 6886b8d390dc7e2f4a2c91b3
                          title: Id
                        created_date:
                          anyOf:
                            - type: string
                            - type: 'null'
                          description: >-
                            When the record was created, as a UTC timestamp in
                            ISO 8601 format. A record Base44 has just created
                            carries a `Z` suffix, and a record read back from
                            storage does not.
                          example: '2026-06-01T09:23:41.481000'
                          title: Created Date
                        updated_date:
                          anyOf:
                            - type: string
                            - type: 'null'
                          description: >-
                            When the record last changed, as a UTC timestamp in
                            ISO 8601 format. A record Base44 has just created
                            carries a `Z` suffix, and a record read back from
                            storage does not.
                          example: '2026-06-04T14:07:02.115000'
                          title: Updated Date
                        created_by:
                          anyOf:
                            - type: string
                            - type: 'null'
                          description: >-
                            Email of the app user who created the record, or
                            `anonymous` when a visitor created it on an app that
                            needs no login. Apps that hide record authorship
                            leave this field out of the response.
                          example: jane@acme.com
                          title: Created By
                        created_by_id:
                          anyOf:
                            - type: string
                            - type: 'null'
                          description: >-
                            ID of the app user who created the record, or
                            `anonymous` when a visitor created it on an app that
                            needs no login.
                          example: 6874b0c2e1a94d0031bb77de
                          title: Created By Id
                        is_sample:
                          anyOf:
                            - type: boolean
                            - type: 'null'
                          description: >-
                            Whether Base44 stored the record as sample data
                            while the app was being built. A record you create
                            reports `false`.
                          example: false
                          title: Is Sample
                      title: EntityRecord
                      type: object
                    title: EntityRecords
                    description: The created records, then the updated ones.
                    example:
                      - id: 6886b8d390dc7e2f4a2c91b4
                        created_date: '2026-06-05T08:12:44.902000Z'
                        updated_date: '2026-06-05T08:12:44.902000Z'
                        created_by: jane@acme.com
                        created_by_id: 6874b0c2e1a94d0031bb77de
                        is_sample: false
                        order_number: A-1002
                        status: draft
                        amount: 1800
                      - id: 6886b8d390dc7e2f4a2c91b3
                        created_date: '2026-06-01T09:23:41.481000Z'
                        updated_date: '2026-06-05T08:12:44.915000Z'
                        created_by: jane@acme.com
                        created_by_id: 6874b0c2e1a94d0031bb77de
                        is_sample: false
                        order_number: A-1001
                        status: paid
                        amount: 4200
                required:
                  - created
                  - updated
                  - records
        '400':
          description: >-
            `records` is empty or holds more than 500 records, a `key` field
            isn't a string, number, integer or boolean field the entity's schema
            declares, a record has no value for a `key` field or one that
            doesn't fit its type, a value is over 20,000 characters on an app
            that limits field size, or the entity is `User`.
        '401':
          description: Missing or invalid credentials.
        '403':
          description: >-
            You don't have access to this app, the entity's `rls` create rule or
            a field-level rule doesn't cover one of the records, or your API key
            is read-only.
        '404':
          description: App not found, or the app has no entity with this name.
        '422':
          description: >-
            `records` or `key` is missing, `records` isn't an array of JSON
            objects, or a new record is missing a required field the entity's
            schema declares or has a value that doesn't match its type.
        '429':
          description: >-
            Rate limit exceeded. The base limit is 25 requests per minute, and
            this endpoint shares it with [Create entity
            records](/api-reference/create-entity-records). See [Rate
            limits](/developers/references/apps-api/get-started/rate-limits) for
            the multiplier your plan gets.
components:
  schemas:
    UpsertPayload:
      properties:
        records:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Records
          description: >-
            The records to create or update, up to 500, each a flat JSON object
            of the fields the entity's schema declares. Every record needs a
            value for each `key` field.
          example:
            - amount: 4200
              order_number: A-1001
              status: paid
            - amount: 1800
              order_number: A-1002
              status: draft
        key:
          anyOf:
            - type: string
            - items:
                type: string
              type: array
          title: Key
          description: >-
            Field, or list of fields, that identifies a record. A stored record
            whose values in these fields match a record you send is updated, and
            otherwise a new record is created.
          example: order_number
      type: object
      required:
        - records
        - key
      title: UpsertPayload
  securitySchemes:
    PersonalAccessTokenAuth:
      type: http
      scheme: bearer
      description: 'Personal access token, sent as `Authorization: Bearer <token>`.'

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.